├── .gitignore
├── .travis.yml
├── LICENSE
├── README.md
├── resources
├── Resources.qrc
├── icons
│ ├── cancel.png
│ ├── convert.png
│ ├── open.png
│ ├── spinner.gif
│ ├── web-to-webm.icns
│ ├── web-to-webm.ico
│ └── web-to-webm.png
└── web-to-webm.rc
├── src
├── converter.cpp
├── converter.h
├── downloader.cpp
├── downloader.h
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── renamer.cpp
├── updater.cpp
├── updater.h
├── updater.ui
├── utilities.cpp
├── utilities.h
├── window.cpp
└── window.h
└── web-to-webm.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | # Object files
2 | *.o
3 | *.ko
4 |
5 | # Libraries
6 | *.lib
7 | *.a
8 |
9 | # Shared objects (inc. Windows DLLs)
10 | *.dll
11 | *.so
12 | *.so.*
13 | *.dylib
14 |
15 | # Executables
16 | *.exe
17 | *.out
18 | *.app
19 |
20 | .DS_Store
21 | *.pro.user
22 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: cpp
2 | compiler:
3 | - gcc
4 | - clang
5 |
6 | before_install:
7 | - sudo add-apt-repository --yes ppa:ubuntu-sdk-team/ppa
8 | - sudo apt-get update -qq
9 | - sudo apt-get install qtbase5-dev qtdeclarative5-dev libqt5webkit5-dev libsqlite3-dev
10 | - sudo apt-get install qt5-default qttools5-dev-tools
11 |
12 | script:
13 | - qmake web-to-webm.pro
14 | - make
15 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 solusipse
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # web-to-webm [](https://travis-ci.org/solusipse/web-to-webm)
2 |
3 | web-to-webm is simple, cross-platform gui tool for extracting clips from any of Youtube videos (and from many other supported services) and converting them to webm format.
4 |
5 | ## Download
6 | For downloads, visit *Releases* page: [https://github.com/solusipse/web-to-webm/releases/latest](https://github.com/solusipse/web-to-webm/releases/latest). There are Windows (64 and 32 bit) and OS X (64 bit) releases.
7 |
8 | If you are on Linux, follow these steps:
9 |
10 | 1. Build web-to-webm (see `Building` section).
11 | 2. Install `youtube-dl` ([download page](http://rg3.github.io/youtube-dl/download.html)):
12 |
13 | - `sudo curl https://yt-dl.org/downloads/2015.02.10.3/youtube-dl -o /usr/local/bin/youtube-dl`
14 | - `sudo chmod a+x /usr/local/bin/youtube-dl`
15 |
16 | 3. Install `ffmpeg` via your package manager.
17 |
18 | Release page: [https://github.com/solusipse/web-to-webm/releases](https://github.com/solusipse/web-to-webm/releases).
19 |
20 | ## Usage
21 | ### Time format
22 | Format is derived from `ffmpeg`. You have to use colons as separators. There are three options:
23 | - just seconds (`ss - ss`, e.g. `5 - 35`),
24 | - minutes and seconds (`mm:ss - mm:ss`, e.g. `15:00 - 15:25`),
25 | - hours, minutes and seconds (`hh:mm:ss - hh:mm:ss`, e.g. `02:05:00 - 02:05:30`).
26 |
27 | You can mix these standards (e.g. `55 - 01:15` which is equivalent of `00:55 - 01:15` or `55 - 75`).
28 |
29 | ## Interface
30 | 
31 |
32 | ## Building
33 | You need `QT5` to build this software. To build web-to-webm, type these commands:
34 |
35 | 1. `qmake-qt5 web-to-webm.pro`,
36 | 2. `make`.
37 |
38 | On `Windows` and `Mac OS X` it will be probably easier to use QT Creator (open .pro file to start).
39 |
40 | ## Supported sites
41 | Since web-to-webm downloading mechanism is based on `yotube-dl` it supports same services. For full list see: http://rg3.github.io/youtube-dl/supportedsites.html.
42 |
43 | ## Changelog
44 |
45 | ### v.0.7.2
46 | - lightweight mode (no player)
47 |
48 | ### v.0.7.1
49 | - asynchronous loading of video details
50 |
51 | ### v.0.7.0
52 | - higher accuracy of conversion percentage bar
53 | - fixed downloading and conversion of clips downloaded from other services than youtube
54 | - minor interface and binary detecting bugfixes
55 | - now it's possible to set custom ffmpeg parameters
56 | - autoupdate
57 | - installer for Windows
58 | - add widget for setting quality and estimating size of output video
59 |
60 | ### v.0.6.0
61 | - added support for other websites than Youtube
62 | - added to log information about output video duration
63 | - added menu option for setting youtube-dl and ffmpeg paths
64 | - added menu option for resetting settings
65 |
66 | ## License
67 | web-to-webm is MIT licensed. Icons are from Font Awesome ([license](http://fortawesome.github.io/Font-Awesome/license/)).
68 |
--------------------------------------------------------------------------------
/resources/Resources.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | icons/cancel.png
4 | icons/convert.png
5 | icons/open.png
6 | icons/web-to-webm.ico
7 | icons/spinner.gif
8 |
9 |
10 |
--------------------------------------------------------------------------------
/resources/icons/cancel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/cancel.png
--------------------------------------------------------------------------------
/resources/icons/convert.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/convert.png
--------------------------------------------------------------------------------
/resources/icons/open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/open.png
--------------------------------------------------------------------------------
/resources/icons/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/spinner.gif
--------------------------------------------------------------------------------
/resources/icons/web-to-webm.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/web-to-webm.icns
--------------------------------------------------------------------------------
/resources/icons/web-to-webm.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/web-to-webm.ico
--------------------------------------------------------------------------------
/resources/icons/web-to-webm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/solusipse/web-to-webm/54892d8cf880c4ac958df521daf0e7293ccda35d/resources/icons/web-to-webm.png
--------------------------------------------------------------------------------
/resources/web-to-webm.rc:
--------------------------------------------------------------------------------
1 | IDI_ICON1 ICON DISCARDABLE "icons/web-to-webm.ico"
--------------------------------------------------------------------------------
/src/converter.cpp:
--------------------------------------------------------------------------------
1 | #include "ui_mainwindow.h"
2 | #include "converter.h"
3 | #include "utilities.h"
4 | #include "window.h"
5 | #include
6 |
7 | Converter::Converter(QObject *parent) : QObject(parent) {
8 | }
9 |
10 | void Converter::start() {
11 | utils.addToLog("Starting conversion.");
12 | utils.killProcesses();
13 |
14 | utils.currentDuration = 0;
15 |
16 | QStringList arguments;
17 | arguments << "-y" << "-hide_banner";
18 | arguments << "-i" << utils.getCurrentRawFilename();
19 |
20 | int bt = win.ui->bitrateValue->text().toInt();
21 |
22 | if (win.ui->menuRemoveAudio->isChecked())
23 | arguments << "-an";
24 | else
25 | bt -= 100;
26 |
27 | if (bt <= 0) bt = 1;
28 | QString bitrate = QString::number(bt);
29 |
30 | if (!bitrate.isEmpty()) {
31 | bitrate.append("K");
32 | arguments << "-b:v" << bitrate;
33 | utils.addToLog("Bitrate set to: " + bitrate);
34 | }
35 |
36 | if (!utils.configGetValue("ffmpeg_params").isEmpty()) {
37 | arguments << utils.configGetValue("ffmpeg_params").split(" ");
38 | utils.addToLog("Used custom parameters: " + utils.configGetValue("ffmpeg_params"));
39 | }
40 |
41 | if (!win.ui->cutFromEdit->text().trimmed().isEmpty() && !win.ui->cutToEdit->text().trimmed().isEmpty()) {
42 | arguments << "-ss" << win.ui->cutFromEdit->text().trimmed();
43 | arguments << "-to" << win.ui->cutToEdit->text().trimmed();
44 | utils.addToLog("Output video length: " + (QTime(0,0,0).addSecs(utils.getTrimmedVideoDuration())).toString("hh:mm:ss"));
45 | utils.currentDuration = utils.getTrimmedVideoDuration();
46 | }
47 |
48 | arguments << utils.getCurrentFilename();
49 |
50 | utils.conversionProcess = new QProcess;
51 | utils.conversionProcess->setProcessChannelMode(QProcess::MergedChannels);
52 | utils.conversionProcess->start(utils.ffmpegBinaryName(), arguments);
53 |
54 | connect(utils.conversionProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(read()));
55 | connect(utils.conversionProcess, SIGNAL(finished(int)), this, SLOT(complete(int)));
56 | }
57 |
58 | void Converter::read() {
59 | QString buffer = utils.conversionProcess->readAllStandardOutput();
60 | QString duration, progress;
61 | QTime durationTime, progressTime;
62 | QRegExp time("\\d\\d\\:\\d\\d\\:\\d\\d\\.\\d\\d");
63 | time.indexIn(buffer);
64 | if (buffer.contains("Duration: ") && utils.currentDuration == 0) {
65 | duration = time.capturedTexts()[0];
66 | durationTime = QTime::fromString(duration, "hh:mm:ss.z");
67 | utils.currentDuration = QTime(0,0).secsTo(durationTime);
68 | } else {
69 | if (buffer != "") {
70 | progress = time.capturedTexts()[0];
71 | if (progress != "") {
72 | progressTime = QTime::fromString(progress, "hh:mm:ss.z");
73 | int percent = double((QTime(0,0).msecsTo(progressTime)) / double(utils.currentDuration*1000))*100;
74 | win.ui->conversionProgressBar->setValue(percent);
75 | }
76 | }
77 | }
78 | if (win.ui->menuFfmpegOutput->isChecked())
79 | utils.addToLog(buffer);
80 | else
81 | utils.addToLog(buffer, false);
82 | }
83 |
84 | void Converter::complete(int code) {
85 | utils.conversionProcess->deleteLater();
86 | utils.conversionProcess = NULL;
87 | win.updateConversionButton();
88 |
89 | if (utils.killed) {
90 | utils.addToLog("Conversion canceled.");
91 | utils.killed = false;
92 | win.toggleConversionButton();
93 | return;
94 | }
95 | if (code != 0) {
96 | utils.addToLog("Error on conversion. Check logs.");
97 | win.toggleConversionButton();
98 | return;
99 | }
100 |
101 | // In case video is so short that ffmpeg do not display
102 | // conversion status
103 | win.ui->conversionProgressBar->setValue(100);
104 |
105 | win.toggleConversionButton();
106 | win.updateConversionButton();
107 |
108 | if (win.ui->menuRemoveRawVideo->isChecked())
109 | utils.removeRawVideo();
110 |
111 | utils.addToLog("Conversion complete.");
112 | utils.addToLog("Saved to: " + utils.getCurrentFilename());
113 |
114 | if (win.ui->menuShowFile->isChecked())
115 | utils.showFileInDirectory();
116 | }
117 |
--------------------------------------------------------------------------------
/src/converter.h:
--------------------------------------------------------------------------------
1 | #ifndef CONVERTER_H
2 | #define CONVERTER_H
3 |
4 | #include
5 |
6 | class Converter : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit Converter(QObject *parent = 0);
11 | void start();
12 |
13 | private:
14 | QString command;
15 |
16 | public slots:
17 | void read();
18 | void complete(int code);
19 |
20 | };
21 |
22 | #endif // CONVERTER_H
23 |
--------------------------------------------------------------------------------
/src/downloader.cpp:
--------------------------------------------------------------------------------
1 | #include "ui_mainwindow.h"
2 | #include "downloader.h"
3 | #include "utilities.h"
4 | #include "window.h"
5 |
6 | Downloader::Downloader(QObject *parent) : QObject(parent) {
7 | }
8 |
9 | void Downloader::start(QString c, QStringList l) {
10 | utils.downloadProcess = new QProcess;
11 | utils.downloadProcess->setProcessChannelMode(QProcess::MergedChannels);
12 | utils.downloadProcess->start(c, l);
13 |
14 | connect(utils.downloadProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(read()));
15 | connect(utils.downloadProcess, SIGNAL(finished(int)), this, SLOT(complete(int)));
16 | }
17 |
18 | void Downloader::read() {
19 | QString buffer = utils.downloadProcess->readAllStandardOutput();
20 |
21 | QRegExp regexp("\\[download\\]\\s+(\\d+)\\.");
22 | regexp.indexIn(buffer);
23 | QString percent = regexp.capturedTexts()[1];
24 | if (percent != "")
25 | win.ui->downloadProgressBar->setValue(percent.toInt());
26 |
27 | if (buffer.contains("has already been downloaded"))
28 | win.ui->downloadProgressBar->setValue(100);
29 |
30 | if (win.ui->menuYoutubedlOutput->isChecked())
31 | utils.addToLog(buffer);
32 | else
33 | utils.addToLog(buffer, false);
34 | }
35 |
36 | void Downloader::complete(int code) {
37 | utils.downloadProcess->deleteLater();
38 | utils.downloadProcess = NULL;
39 |
40 | if (utils.killed) {
41 | utils.addToLog("Downloading canceled.");
42 | utils.killed = false;
43 | win.toggleConversionButton();
44 | return;
45 | }
46 | if (code != 0) {
47 | utils.addToLog("Download error.");
48 | win.toggleConversionButton();
49 | return;
50 | }
51 |
52 | utils.addToLog("Download complete");
53 |
54 | if (win.ui->menuDontConvert->isChecked()) {
55 | utils.addToLog("User decided not to convert. Downloaded video saved to: " + utils.getCurrentRawFilename());
56 | win.toggleConversionButton();
57 | return;
58 | }
59 |
60 | utils.convert.start();
61 | }
62 |
--------------------------------------------------------------------------------
/src/downloader.h:
--------------------------------------------------------------------------------
1 | #ifndef DOWNLOADER_H
2 | #define DOWNLOADER_H
3 |
4 | #include
5 | #include
6 |
7 | class Downloader : public QObject {
8 | Q_OBJECT
9 |
10 | public:
11 | explicit Downloader(QObject *parent = 0);
12 | void start(QString c, QStringList l);
13 |
14 | private:
15 | QString command;
16 |
17 | public slots:
18 | void read();
19 | void complete(int code);
20 |
21 | };
22 |
23 |
24 | #endif // DOWNLOADER_H
25 |
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include
3 |
4 | int main(int argc, char *argv[]) {
5 | QApplication a(argc, argv);
6 | MainWindow w;
7 | w.show();
8 |
9 | return a.exec();
10 | }
11 |
--------------------------------------------------------------------------------
/src/mainwindow.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 | #include "ui_mainwindow.h"
3 | #include "downloader.h"
4 | #include "utilities.h"
5 | #include "window.h"
6 | #include "updater.h"
7 |
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 |
15 |
16 | MainWindow::MainWindow(QWidget *parent) :
17 | QMainWindow(parent), ui(new Ui::MainWindow) {
18 |
19 | ui->setupUi(this);
20 | win.ui = ui;
21 |
22 | this->setWindowTitle("web-to-webm v." VERSION);
23 |
24 | win.setTheme();
25 | utils.setCommons();
26 | utils.configInit();
27 | utils.configLoadAll();
28 | win.lockAllControls(true);
29 | win.setPlayerHtml();
30 | win.detectMode(this);
31 | utils.addToLog("Initialised.");
32 | }
33 |
34 | MainWindow::~MainWindow() {
35 | utils.configSaveAll();
36 | utils.killProcesses();
37 | delete ui;
38 | }
39 |
40 | void MainWindow::on_urlEdit_returnPressed() {
41 | utils.startProcessQueue(win.ui->urlEdit->text());
42 | }
43 |
44 | void MainWindow::on_selectSavePath_clicked() {
45 | QString filename = QFileDialog::getSaveFileName(this,
46 | tr("Select location for converted film"), QDir::currentPath(), tr("Webm (*.webm)") );
47 |
48 | if (filename.isEmpty())
49 | return;
50 |
51 | utils.pathChanged = true;
52 | utils.currentFileName = filename;
53 |
54 | win.setFilename();
55 | }
56 |
57 | void MainWindow::on_startConversion_clicked() {
58 | win.updateConversionButton();
59 | win.resetProgress();
60 | if (ui->startConversion->isChecked()) {
61 | if (!utils.checkUrl())
62 | return;
63 | utils.getFileName();
64 |
65 | QStringList arguments;
66 | arguments << "-f" << utils.getVideoQuality() << "-o";
67 | arguments << utils.getCurrentRawFilename() << utils.currentVideoUrl;
68 |
69 | utils.download.start(utils.getBinaryName(), arguments);
70 | } else {
71 | win.toggleConversionButton();
72 | utils.killProcesses();
73 | }
74 | }
75 |
76 | void MainWindow::on_menuAbout_triggered() {
77 | QMessageBox::about(this, "web-to-webm about",
78 | "web-to-webm " VERSION "\n\n"
79 | "This software is open source (MIT licensed). "
80 | "For more informations see:\n"
81 | "https://github.com/solusipse/web-to-webm.");
82 | }
83 |
84 | void MainWindow::on_qualityComboBox_currentIndexChanged(int index) {
85 | win.setFilename();
86 | win.resetProgress();
87 | utils.addToLog("Changed resolution to: " + utils.currentQualityList[index][0]);
88 | }
89 |
90 | void MainWindow::on_menuWebsite_triggered() {
91 | QDesktopServices::openUrl(QUrl("https://github.com/solusipse/web-to-webm"));
92 | }
93 |
94 | void MainWindow::on_menuDefaultDownloadPath_triggered() {
95 | QString dir = QFileDialog::getExistingDirectory(this, tr("Open Directory"),
96 | QDir().homePath(), QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
97 | if (!dir.isEmpty())
98 | utils.configSetValue("default_path", dir);
99 | }
100 |
101 | void MainWindow::on_menuExit_triggered() {
102 | qApp->exit();
103 | }
104 |
105 | void MainWindow::on_menuClearLog_triggered() {
106 | win.ui->logBox->clear();
107 | }
108 |
109 | void MainWindow::on_menuShowLog_triggered() {
110 | QDialog dialog(this, Qt::Window);
111 | QPlainTextEdit *box = new QPlainTextEdit(&dialog);
112 | QVBoxLayout *layout = new QVBoxLayout;
113 | dialog.resize(640, 480);
114 | dialog.setWindowTitle("web-to-webm log");
115 | layout->addWidget(box);
116 | dialog.setLayout(layout);
117 | box->setReadOnly(true);
118 | box->setPlainText(utils.log);
119 | dialog.exec();
120 | }
121 |
122 | void MainWindow::on_menuNew_triggered() {
123 | utils.newVideo();
124 | }
125 |
126 | void MainWindow::on_menuCustomYoutubedlPath_triggered() {
127 | bool ok;
128 | QString path = QInputDialog::getText(this,
129 | tr("Set custom youtube-dl path"),
130 | tr("youtube-dl absolute path (leave blank for default):"), QLineEdit::Normal,
131 | utils.configGetValue("youtubedl_path"), &ok);
132 | if (ok)
133 | utils.configSetValue("youtubedl_path", path);
134 | }
135 |
136 | void MainWindow::on_menuCustomFfmpegPath_triggered() {
137 | bool ok;
138 | QString path = QInputDialog::getText(this,
139 | tr("Set custom ffmpeg path"),
140 | tr("ffmpeg absolute path (leave blank for default):"), QLineEdit::Normal,
141 | utils.configGetValue("ffmpeg_path"), &ok);
142 | if (ok)
143 | utils.configSetValue("ffmpeg_path", path);
144 | }
145 |
146 | void MainWindow::on_menuResetAllSettings_triggered() {
147 | QMessageBox::StandardButton reply = QMessageBox::question(this,
148 | "Reset settings", "Are you sure you want to reset all settings?",
149 | QMessageBox::Yes|QMessageBox::No);
150 |
151 | if (reply != QMessageBox::Yes)
152 | return;
153 |
154 | QSettings settings(QSettings::IniFormat, QSettings::UserScope, "solusipse", "web-to-webm");
155 | for (int i = 0; i < settings.allKeys().length(); i++)
156 | settings.remove(settings.allKeys()[i]);
157 | utils.configInit();
158 | }
159 |
160 | void MainWindow::on_menuFfmpegCustomParams_triggered() {
161 | bool ok;
162 | QString path = QInputDialog::getText(this,
163 | tr("Set custom ffmpeg parameters"),
164 | tr("youtube-dl ffmpeg (e.g. -b:v 2M, leave blank for default):"), QLineEdit::Normal,
165 | utils.configGetValue("ffmpeg_params"), &ok);
166 | if (ok)
167 | utils.configSetValue("ffmpeg_params", path);
168 | }
169 |
170 | void MainWindow::on_menuUpdate_triggered() {
171 | Updater *u = new Updater(this);
172 | u->show();
173 | }
174 |
175 | void MainWindow::on_bitrateValue_textChanged() {
176 | utils.updateBitrate();
177 | }
178 |
179 | void MainWindow::on_cutFromEdit_textChanged() {
180 | utils.updateBitrate();
181 | }
182 |
183 | void MainWindow::on_cutToEdit_textChanged() {
184 | utils.updateBitrate();
185 | }
186 |
187 | void MainWindow::on_menuLtMode_triggered() {
188 | if (win.ui->player == NULL) {
189 | utils.configSetValue("light_mode", "false");
190 | qApp->quit();
191 | QProcess::startDetached(qApp->arguments()[0], qApp->arguments());
192 | return;
193 | }
194 |
195 | utils.configSetValue("light_mode", "true");
196 | win.setLightMode(this);
197 | }
198 |
--------------------------------------------------------------------------------
/src/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include
6 |
7 | namespace Ui {
8 | class MainWindow;
9 | }
10 |
11 | class MainWindow : public QMainWindow
12 | {
13 | Q_OBJECT
14 |
15 | public:
16 | explicit MainWindow(QWidget *parent = 0);
17 | ~MainWindow();
18 |
19 | private slots:
20 | void on_urlEdit_returnPressed();
21 | void on_selectSavePath_clicked();
22 | void on_startConversion_clicked();
23 | void on_menuAbout_triggered();
24 | void on_qualityComboBox_currentIndexChanged(int index);
25 | void on_menuWebsite_triggered();
26 | void on_menuDefaultDownloadPath_triggered();
27 | void on_menuExit_triggered();
28 | void on_menuClearLog_triggered();
29 | void on_menuShowLog_triggered();
30 | void on_menuNew_triggered();
31 | void on_menuCustomFfmpegPath_triggered();
32 | void on_menuCustomYoutubedlPath_triggered();
33 | void on_menuResetAllSettings_triggered();
34 | void on_menuFfmpegCustomParams_triggered();
35 | void on_menuUpdate_triggered();
36 | void on_bitrateValue_textChanged();
37 | void on_cutFromEdit_textChanged();
38 | void on_cutToEdit_textChanged();
39 | void on_menuLtMode_triggered();
40 |
41 | private:
42 | Ui::MainWindow *ui;
43 | };
44 |
45 | #endif // MAINWINDOW_H
46 |
--------------------------------------------------------------------------------
/src/mainwindow.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainWindow
4 |
5 |
6 |
7 | 0
8 | 0
9 | 1024
10 | 600
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 500
22 | 0
23 |
24 |
25 |
26 | web-to-webm
27 |
28 |
29 |
30 | :/icons/web-to-webm.ico:/icons/web-to-webm.ico
31 |
32 |
33 |
34 | -
35 |
36 |
37 | QFrame::StyledPanel
38 |
39 |
40 | QFrame::Sunken
41 |
42 |
43 |
44 | 12
45 |
46 |
47 | 12
48 |
49 |
50 | 12
51 |
52 |
53 | 12
54 |
55 |
-
56 |
57 |
58 | Url to Youtube video
59 |
60 |
61 |
62 | -
63 |
64 |
65 | true
66 |
67 |
68 | Youtube video title
69 |
70 |
71 |
72 |
73 |
74 |
75 | -
76 |
77 |
78 |
79 | 0
80 | 0
81 |
82 |
83 |
84 |
85 | 200
86 | 0
87 |
88 |
89 |
90 | QFrame::NoFrame
91 |
92 |
93 | QFrame::Raised
94 |
95 |
96 |
97 | 0
98 |
99 |
100 | 8
101 |
102 |
103 | 0
104 |
105 |
106 | 0
107 |
108 |
-
109 |
110 |
111 |
112 | 0
113 | 0
114 |
115 |
116 |
117 |
118 | 200
119 | 0
120 |
121 |
122 |
123 | false
124 |
125 |
126 | body{background:#333;}
127 |
128 |
129 |
130 | about:blank
131 |
132 |
133 |
134 |
135 | -
136 |
137 |
138 |
139 | 200
140 | 0
141 |
142 |
143 |
144 |
145 | 200
146 | 16777215
147 |
148 |
149 |
150 | QFrame::StyledPanel
151 |
152 |
153 | QFrame::Raised
154 |
155 |
156 |
157 | 12
158 |
159 |
160 | 12
161 |
162 |
163 | 12
164 |
165 |
166 | 12
167 |
168 |
-
169 |
170 |
171 | QFrame::NoFrame
172 |
173 |
174 | QFrame::Raised
175 |
176 |
177 |
178 | 0
179 |
180 |
181 | 0
182 |
183 |
184 | 0
185 |
186 |
187 | 0
188 |
189 |
-
190 |
191 |
192 |
193 |
194 |
195 | 16
196 |
197 |
198 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
199 |
200 |
201 | Cut from
202 |
203 |
204 |
205 | -
206 |
207 |
208 | 16
209 |
210 |
211 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter
212 |
213 |
214 | Cut to
215 |
216 |
217 |
218 |
219 |
220 |
221 | -
222 |
223 |
224 | QFrame::NoFrame
225 |
226 |
227 | QFrame::Raised
228 |
229 |
230 |
231 | 0
232 |
233 |
234 | 0
235 |
236 |
237 | 0
238 |
239 |
240 | 0
241 |
242 |
-
243 |
244 |
245 |
246 |
247 |
248 | 5
249 |
250 |
251 | Bitrate (k)
252 |
253 |
254 |
255 | -
256 |
257 |
258 | true
259 |
260 |
261 | Est. size
262 |
263 |
264 |
265 |
266 |
267 |
268 | -
269 |
270 |
271 | QFrame::NoFrame
272 |
273 |
274 | QFrame::Raised
275 |
276 |
277 |
278 | 0
279 |
280 |
281 | 0
282 |
283 |
284 | 0
285 |
286 |
287 | 0
288 |
289 |
-
290 |
291 |
292 | true
293 |
294 |
295 | Filename
296 |
297 |
298 |
299 | -
300 |
301 |
302 |
303 | 0
304 | 0
305 |
306 |
307 |
308 |
309 | 35
310 | 35
311 |
312 |
313 |
314 |
315 | 35
316 | 35
317 |
318 |
319 |
320 | ...
321 |
322 |
323 |
324 | :/icons/open.png:/icons/open.png
325 |
326 |
327 |
328 |
329 |
330 |
331 | -
332 |
333 |
334 | QFrame::NoFrame
335 |
336 |
337 | QFrame::Raised
338 |
339 |
340 |
341 | 0
342 |
343 |
344 | 0
345 |
346 |
347 | 0
348 |
349 |
350 | 0
351 |
352 |
-
353 |
354 |
355 | false
356 |
357 |
358 | -1
359 |
360 |
361 |
362 | -
363 |
364 |
365 |
366 | 35
367 | 35
368 |
369 |
370 |
371 |
372 | 35
373 | 35
374 |
375 |
376 |
377 | ...
378 |
379 |
380 |
381 | :/icons/convert.png:/icons/convert.png
382 |
383 |
384 | true
385 |
386 |
387 | false
388 |
389 |
390 |
391 |
392 |
393 |
394 | -
395 |
396 |
397 | Qt::Vertical
398 |
399 |
400 | QSizePolicy::Fixed
401 |
402 |
403 |
404 | 20
405 | 20
406 |
407 |
408 |
409 |
410 | -
411 |
412 |
413 | Downloading
414 |
415 |
416 |
417 | -
418 |
419 |
420 | 0
421 |
422 |
423 | Qt::AlignCenter
424 |
425 |
426 |
427 | -
428 |
429 |
430 | Conversion
431 |
432 |
433 |
434 | -
435 |
436 |
437 | 100
438 |
439 |
440 | 0
441 |
442 |
443 | Qt::AlignCenter
444 |
445 |
446 | true
447 |
448 |
449 | QProgressBar::TopToBottom
450 |
451 |
452 |
453 | -
454 |
455 |
456 | true
457 |
458 |
459 | Qt::ImhNone
460 |
461 |
462 | QFrame::NoFrame
463 |
464 |
465 | false
466 |
467 |
468 | true
469 |
470 |
471 | false
472 |
473 |
474 |
475 |
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
544 |
545 |
546 | true
547 |
548 |
549 | Remove audio
550 |
551 |
552 |
553 |
554 | Set default download location
555 |
556 |
557 |
558 |
559 | About
560 |
561 |
562 |
563 |
564 | true
565 |
566 |
567 | true
568 |
569 |
570 | Remove raw video
571 |
572 |
573 |
574 |
575 | true
576 |
577 |
578 | Set custom parameters for ffmpeg
579 |
580 |
581 |
582 |
583 | true
584 |
585 |
586 | Add custom parameters for youtube-dl
587 |
588 |
589 |
590 |
591 | true
592 |
593 |
594 | Set custom youtube-dl path
595 |
596 |
597 |
598 |
599 | true
600 |
601 |
602 | Set custom ffmpeg path
603 |
604 |
605 |
606 |
607 | Website
608 |
609 |
610 |
611 |
612 | true
613 |
614 |
615 | Don't convert (download only)
616 |
617 |
618 |
619 |
620 | Show full log
621 |
622 |
623 |
624 |
625 | Clear log
626 |
627 |
628 |
629 |
630 | New
631 |
632 |
633 |
634 |
635 | Exit
636 |
637 |
638 |
639 |
640 | true
641 |
642 |
643 | Open output directory after conversion
644 |
645 |
646 |
647 |
648 | true
649 |
650 |
651 | true
652 |
653 |
654 | Display youtube-dl output
655 |
656 |
657 |
658 |
659 | true
660 |
661 |
662 | true
663 |
664 |
665 | Display ffmpeg output
666 |
667 |
668 |
669 |
670 | Reset all settings
671 |
672 |
673 |
674 |
675 | false
676 |
677 |
678 | Advanced settings
679 |
680 |
681 |
682 |
683 | Check for updates
684 |
685 |
686 |
687 |
688 | true
689 |
690 |
691 | Lightweight mode
692 |
693 |
694 |
695 |
696 |
697 |
698 | QWebView
699 | QWidget
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
--------------------------------------------------------------------------------
/src/renamer.cpp:
--------------------------------------------------------------------------------
1 | /* This program replaces old binary with new,
2 | * downloaded from update serwer.
3 | * This should be rewritten as standalone
4 | * QT app which does the whole update
5 | * procedure.
6 | */
7 |
8 | #include
9 |
10 | #ifdef _WIN32
11 | #define SYSTEM 0
12 | #include
13 | #else
14 | #define SYSTEM 1
15 | #include
16 | #include
17 | #include
18 | #endif
19 |
20 | void log(const char *l);
21 | void windows_procedure(char *argv);
22 | void unix_procedure(char *argv);
23 | void windows_rename();
24 | void unix_rename();
25 | void change_directory();
26 |
27 | int main (int argc, char *argv[]) {
28 | if (SYSTEM == 0)
29 | windows_procedure(argv[1]);
30 | else
31 | unix_procedure(argv[0]);
32 |
33 | return 0;
34 | }
35 |
36 | void log(const char *l) {
37 | FILE *f = fopen("updatelog.txt", "a");
38 | if (f == NULL) {
39 | printf("Can't open updatelog.txt\n");
40 | exit(1);
41 | }
42 | fprintf(f, "%s\n", l);
43 | fclose(f);
44 |
45 | printf("%s\n", l);
46 | }
47 |
48 | #ifdef _WIN32
49 | void windows_procedure(char *argv) {
50 | log("Detected WINDOWS system, waiting for main process to die.");
51 | printf("PID: %s\n", argv);
52 | DWORD dwExitCode = 259;
53 | while(1) {
54 | HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, atoi(argv));
55 | if(GetExitCodeProcess(h, &dwExitCode))
56 | CloseHandle(h);
57 | else
58 | break;
59 |
60 | Sleep(1000);
61 | }
62 | printf("Process is dead now. Starting update.");
63 | windows_rename();
64 | }
65 |
66 | void windows_rename() {
67 | remove("web-to-webm.old");
68 |
69 | int s;
70 | char o[] = "web-to-webm.exe";
71 | char n[] = "web-to-webm.old";
72 | s = rename(o, n);
73 | if (s == 0)
74 | log("Created backup of an old binary.");
75 | else
76 | log("Error on creating backup.");
77 |
78 | char o_[] = "update";
79 | char n_[] = "web-to-webm.exe";
80 | s = rename(o_ , n_);
81 | if (s == 0)
82 | log("New binary installed");
83 | else {
84 | log("Error on installing new binary. Abort.");
85 | exit(1);
86 | }
87 |
88 | printf("Starting web-to-webm...");
89 |
90 | STARTUPINFO si;
91 | PROCESS_INFORMATION pi;
92 | ZeroMemory(&si, sizeof(si));
93 | si.cb = sizeof(si);
94 | ZeroMemory(&pi, sizeof(pi));
95 | CreateProcess("web-to-webm.exe", NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
96 |
97 | log("Update complete!");
98 | }
99 | #endif
100 |
101 |
102 | void unix_procedure(char *argv) {
103 | #ifndef _WIN32
104 | // This is necessary for app bundles on OS X
105 | char path[1024];
106 | strncpy(path, argv, strlen(argv)-7);
107 | path[strlen(argv)-7] = NULL;
108 | chdir(path);
109 |
110 | remove("web-to-webm.old");
111 |
112 | int s;
113 | char o[] = "web-to-webm";
114 | char n[] = "web-to-webm.old";
115 | s = rename(o, n);
116 | if (s == 0)
117 | log("Created backup of an old binary.");
118 | else
119 | log("Error on creating backup.");
120 |
121 | char o_[] = "update";
122 | char n_[] = "web-to-webm";
123 | s = rename(o_ , n_);
124 | if (s == 0)
125 | log("New binary installed");
126 | else {
127 | log("Error on installing new binary. Abort.");
128 | exit(1);
129 | }
130 |
131 | system("chmod a+x web-to-webm");
132 |
133 | printf("Starting web-to-webm...");
134 | system("./web-to-webm");
135 | #endif
136 | }
137 |
138 |
--------------------------------------------------------------------------------
/src/updater.cpp:
--------------------------------------------------------------------------------
1 | #include "updater.h"
2 | #include "ui_updater.h"
3 | #include "utilities.h"
4 |
5 | #include
6 | #include
7 |
8 | /* TODO:
9 | * In the future this class needs big improvements,
10 | * such as checking checksum, xml parsing, adding
11 | * download progress bar and some archive unpacker
12 | * for updates. We'll probably need also some mirrors.
13 | */
14 |
15 | #if _WIN32 || _WIN64
16 | #if _WIN64
17 | #define WINARCH "32"
18 | #else
19 | #define WINARCH "64"
20 | #endif
21 | #else
22 | #define WINARCH ""
23 | #endif
24 |
25 |
26 | Updater::Updater(QWidget *parent) : QDialog(parent), ui(new Ui::Updater) {
27 | ui->setupUi(this);
28 | ui->plainTextEdit->setStyleSheet("QPlainTextEdit{background:#383838; color: #888;}");
29 | addToLog("After update restart is required, so finish your work before you start.");
30 | }
31 |
32 | Updater::~Updater() {
33 | delete ui;
34 | }
35 |
36 | void Updater::start() {
37 | addToLog("Started update");
38 | checkForUpdates();
39 | }
40 |
41 | void Updater::checkForUpdates() {
42 | QNetworkAccessManager *manager = new QNetworkAccessManager();
43 | connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(replyFinished(QNetworkReply *)));
44 | manager->get(QNetworkRequest(QUrl("http://solusipse.net/software/web-to-webm/version.txt")));
45 | }
46 |
47 | void Updater::replyFinished(QNetworkReply *reply) {
48 | if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 404) {
49 | addToLog("Could not get current version. Aborting.");
50 | ui->progressBar->setValue(0);
51 | return;
52 | }
53 |
54 | QString newestVersion = reply->readAll();
55 | addToLog("Connected to update server.");
56 | incrementProgressBar();
57 | addToLog("Your web-to-webm version is: " VERSION);
58 | if (newestVersion == VERSION) {
59 | addToLog("There are no updates.");
60 | ui->progressBar->setValue(5);
61 | return;
62 | }
63 |
64 | addToLog("Newest version is: " + newestVersion);
65 | addToLog("Downloading...");
66 | incrementProgressBar();
67 |
68 | QNetworkAccessManager *manager = new QNetworkAccessManager();
69 | connect(manager, SIGNAL(finished(QNetworkReply *)), this, SLOT(downloadFinished(QNetworkReply *)));
70 | manager->get(QNetworkRequest(QUrl("http://solusipse.net/software/web-to-webm/" + prepareBinaryName(newestVersion))));
71 | }
72 |
73 | void Updater::downloadFinished(QNetworkReply *reply) {
74 | if (reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt() == 404) {
75 | addToLog("Could not download proper binary. Aborting.");
76 | ui->progressBar->setValue(0);
77 | return;
78 | }
79 | addToLog("Download complete.");
80 | incrementProgressBar();
81 | QFile f(QCoreApplication::applicationDirPath() + "/update");
82 | if (f.open(QIODevice::WriteOnly)) {
83 | f.write(reply->readAll());
84 | f.close();
85 | }
86 | addToLog("Saved to file.");
87 | addToLog("Application will be restarted now.");
88 |
89 | QString pid = QString::number(QCoreApplication::applicationPid());
90 |
91 | QProcess *proc = new QProcess(this);
92 | proc->startDetached(QCoreApplication::applicationDirPath() + "/renamer " + pid);
93 |
94 | qApp->exit();
95 | }
96 |
97 | void Updater::addToLog(QString s) {
98 | ui->plainTextEdit->appendPlainText(s);
99 | }
100 |
101 | void Updater::incrementProgressBar() {
102 | ui->progressBar->setValue(ui->progressBar->value() + 1);
103 | }
104 |
105 | QString Updater::prepareBinaryName(QString v) {
106 | if (SYSTEM == 0)
107 | return "win-" + QString(WINARCH) + "-web-to-webm-" + v;
108 | if (SYSTEM == 1)
109 | return "mac-web-to-webm-" + v;
110 | if (SYSTEM == 2)
111 | return "linux-web-to-webm-" + v;
112 | }
113 |
114 | void Updater::on_buttonStart_clicked()
115 | {
116 | utils.killProcesses();
117 | start();
118 | }
119 |
--------------------------------------------------------------------------------
/src/updater.h:
--------------------------------------------------------------------------------
1 | #ifndef UPDATER_H
2 | #define UPDATER_H
3 |
4 | #include
5 | #include
6 |
7 | namespace Ui {
8 | class Updater;
9 | }
10 |
11 | class Updater : public QDialog
12 | {
13 | Q_OBJECT
14 |
15 | public:
16 | explicit Updater(QWidget *parent = 0);
17 | ~Updater();
18 |
19 | private:
20 | Ui::Updater *ui;
21 | void checkForUpdates();
22 | void addToLog(QString s);
23 | void start();
24 | void incrementProgressBar();
25 |
26 | QString prepareBinaryName(QString v);
27 |
28 | public slots:
29 | void replyFinished(QNetworkReply *reply);
30 | void downloadFinished(QNetworkReply *reply);
31 | private slots:
32 | void on_buttonStart_clicked();
33 | };
34 |
35 | #endif // UPDATER_H
36 |
--------------------------------------------------------------------------------
/src/updater.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Updater
4 |
5 |
6 |
7 | 0
8 | 0
9 | 320
10 | 240
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 320
22 | 240
23 |
24 |
25 |
26 |
27 | 320
28 | 240
29 |
30 |
31 |
32 | Checking for updates
33 |
34 |
35 |
36 |
37 | 10
38 | 10
39 | 301
40 | 181
41 |
42 |
43 |
44 | QFrame::NoFrame
45 |
46 |
47 | QFrame::Raised
48 |
49 |
50 |
51 | 0
52 |
53 |
54 | 0
55 |
56 |
57 | 0
58 |
59 |
60 | 0
61 |
62 | -
63 |
64 |
65 | QFrame::NoFrame
66 |
67 |
68 | true
69 |
70 |
71 |
72 | -
73 |
74 |
75 | 3
76 |
77 |
78 | 0
79 |
80 |
81 | Qt::AlignCenter
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 10
91 | 197
92 | 301
93 | 35
94 |
95 |
96 |
97 |
98 | 16777215
99 | 35
100 |
101 |
102 |
103 | Start update
104 |
105 |
106 |
107 |
108 |
109 |
110 |
--------------------------------------------------------------------------------
/src/utilities.cpp:
--------------------------------------------------------------------------------
1 | #include "ui_mainwindow.h"
2 | #include "utilities.h"
3 | #include "window.h"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | Utilities utils;
13 |
14 | Utilities::Utilities() : settings("solusipse", "web-to-webm") {
15 | killed = false;
16 | }
17 |
18 | void Utilities::setCommons() {
19 | QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
20 | win.ui->player->settings()->setAttribute(QWebSettings::PluginsEnabled, true);
21 | }
22 |
23 | void Utilities::addToLog(QString line, bool display) {
24 | if (line.length() < 3)
25 | return;
26 | line.prepend("[" + QTime().currentTime().toString() + "] ");
27 | if (display)
28 | win.ui->logBox->appendHtml(line);
29 |
30 | line.replace("
", "").replace("", "").replace("", "");
31 | if (!log.contains("\n"))
32 | log.append(line + "\n");
33 | else
34 | log.append(line);
35 | }
36 |
37 | bool Utilities::checkUrl() {
38 | if (currentVideoUrl.isEmpty()) {
39 | addToLog("Add valid video first.");
40 | return false;
41 | }
42 | addToLog("
Started downloading video:
" + win.ui->urlEdit->text());
43 | return true;
44 | }
45 |
46 | QVector< QVector > Utilities::createQualityList(QString formats) {
47 | QVector< QVector > list;
48 | QStringList formatsList = formats.split("\n");
49 |
50 | /*
51 | * there are always clips in webm and mp4 with same resolution
52 | * since mp4 provides better quality and there is sometimes
53 | * higher quality in mp4 format available, script is excluding webm
54 | * at this moment
55 | */
56 |
57 | for (int i = formatsList.length()-1; i >= 0 ; i--) {
58 | if (!formatsList[i].contains("webm"))
59 | if (!formatsList[i].contains("audio only"))
60 | if (!formatsList[i].contains("video only")) {
61 | QRegExp resolution("\\d{3,4}x\\d{3,4}");
62 | resolution.indexIn(formatsList[i]);
63 | QRegExp format("\\w\\w\\w");
64 | format.indexIn(formatsList[i]);
65 |
66 | QString strResolution = resolution.capturedTexts()[0];
67 | QString strFormat = format.capturedTexts()[0];
68 |
69 | if (strFormat != "" && formatsList[i].contains("unknown"))
70 | strResolution = "unknown";
71 |
72 | if (strResolution != "" && strFormat != "") {
73 | QString strCode = formatsList[i].split(" ")[0];
74 | QVector single;
75 | single.append(strResolution);
76 | single.append(strCode);
77 | single.append(strFormat);
78 | list.append(single);
79 | }
80 | }
81 | }
82 | return list;
83 | }
84 |
85 | QString Utilities::getVideoQuality() {
86 | return currentQualityList[win.ui->qualityComboBox->currentIndex()][1];
87 | }
88 |
89 | QString Utilities::getFileName() {
90 | return currentID + "-" + currentQualityList[win.ui->qualityComboBox->currentIndex()][1] + "." + currentQualityList[win.ui->qualityComboBox->currentIndex()][2];
91 | }
92 |
93 | void Utilities::killProcesses() {
94 | if (utils.downloadProcess != NULL) {
95 | killed = true;
96 | utils.downloadProcess->kill();
97 | }
98 | if (utils.conversionProcess != NULL) {
99 | killed = true;
100 | utils.conversionProcess->kill();
101 | }
102 | }
103 |
104 | QString Utilities::getBinaryName() {
105 | if (!configGetValue("youtubedl_path").isEmpty())
106 | return configGetValue("youtubedl_path");
107 |
108 | if (SYSTEM == 0)
109 | return "youtube-dl.exe";
110 | if (SYSTEM == 1)
111 | return QCoreApplication::applicationDirPath() + "/youtube-dl";
112 | return "youtube-dl";
113 | }
114 |
115 | QString Utilities::ffmpegBinaryName() {
116 | if (!configGetValue("ffmpeg_path").isEmpty())
117 | return configGetValue("ffmpeg_path");
118 |
119 | if (SYSTEM == 0)
120 | return "ffmpeg.exe";
121 | if (SYSTEM == 1)
122 | return QCoreApplication::applicationDirPath() + "/ffmpeg";
123 | return "ffmpeg";
124 | }
125 |
126 | QString Utilities::getCurrentRawFilename() {
127 | QString path = QFileInfo(getCurrentFilename()).absolutePath();
128 | QString name = QFileInfo(getCurrentFilename()).baseName();
129 | return path + "/" + name + "." + currentQualityList[win.ui->qualityComboBox->currentIndex()][2];
130 | }
131 |
132 | QString Utilities::getCurrentFilename() {
133 | if (pathChanged)
134 | return currentFileName;
135 |
136 | return getDefaultFilename();
137 | }
138 |
139 | QString Utilities::getDefaultFilename() {
140 | if (configGetValue("default_path").isEmpty())
141 | return QDir().homePath() + "/" + QFileInfo(getFileName()).baseName() + ".webm";
142 | return configGetValue("default_path") + "/" + QFileInfo(getFileName()).baseName() + ".webm";
143 | }
144 |
145 | int Utilities::getTrimmedVideoDuration() {
146 | QString cutFrom = win.ui->cutFromEdit->text();
147 | QString cutTo = win.ui->cutToEdit->text();
148 | int time = parseTime(cutFrom).secsTo(parseTime(cutTo));
149 | return time;
150 | }
151 |
152 | QTime Utilities::parseTime(QString s) {
153 | int occurences = s.count(":");
154 |
155 | if (occurences == 0) {
156 | return QTime(0,0,0).addSecs(s.toInt());
157 | }
158 | if (occurences == 1) {
159 | return QTime::fromString(s, "mm:ss");
160 | }
161 | if (occurences == 2) {
162 | return QTime::fromString(s, "hh:mm:ss");
163 | }
164 |
165 | return QTime();
166 | }
167 |
168 | void Utilities::startProcessQueue(QString url) {
169 | addToLog("Loading video details.");
170 | win.setLoaderHtml();
171 |
172 | currentVideoUrl = url;
173 |
174 | cmdsProcessQueue.clear();
175 | // Title
176 | cmdsProcessQueue << getBinaryName() + " -e " + url;
177 | // ID
178 | cmdsProcessQueue << getBinaryName() + " --get-id " + url;
179 | // Quality list
180 | cmdsProcessQueue << getBinaryName() + " -F " + url;
181 |
182 | if (processQueue != NULL) {
183 | processQueue->blockSignals(true);
184 | processQueue->kill();
185 | }
186 |
187 | processQueue = new QProcess;
188 | processQueue->setProcessChannelMode(QProcess::MergedChannels);
189 | processQueue->start(cmdsProcessQueue[0]);
190 |
191 | processQueue->blockSignals(false);
192 |
193 | connect(processQueue, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessQueue()));
194 | connect(processQueue, SIGNAL(finished(int)), this, SLOT(nextProcessQueue(int)));
195 | connect(processQueue, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorProcessQueue()));
196 | }
197 |
198 | void Utilities::errorProcessQueue() {
199 | addToLog("Could not open youtube-dl. Check if binary exists.");
200 | win.setPlayerHtml();
201 | }
202 |
203 | void Utilities::newVideo() {
204 | utils.killProcesses();
205 | win.setPlayerHtml();
206 | win.ui->titleEdit->clear();
207 | win.ui->urlEdit->clear();
208 | win.reset();
209 | win.lockAllControls(true);
210 | }
211 |
212 | void Utilities::readProcessQueue() {
213 | QString line = QString::fromLocal8Bit(processQueue->readAll());
214 | if (cmdsProcessQueue.length() >= 1) {
215 |
216 | if (cmdsProcessQueue.length() == 3) {
217 | if (line.contains("is not a valid URL.") || line.contains("ERROR: Unable to download webpage: "))
218 | currentVideoUrl = "error_url";
219 | else
220 | currentTitle = line.simplified();
221 | }
222 | if (cmdsProcessQueue.length() == 2)
223 | currentID = line.simplified();
224 |
225 | cmdsProcessQueue.removeFirst();
226 | }
227 | else {
228 | currentQualityList = createQualityList(line);
229 | }
230 | }
231 |
232 | void Utilities::nextProcessQueue(int c) {
233 | if (cmdsProcessQueue.length() <= 0 || currentVideoUrl == "error_url" || c != 0) {
234 | loadVideo(currentVideoUrl);
235 | return;
236 | }
237 |
238 | processQueue->kill();
239 | processQueue = new QProcess;
240 | processQueue->start(cmdsProcessQueue[0]);
241 |
242 | connect(processQueue, SIGNAL(readyReadStandardOutput()), this, SLOT(readProcessQueue()));
243 | connect(processQueue, SIGNAL(finished(int)), this, SLOT(nextProcessQueue(int)));
244 | }
245 |
246 | void Utilities::loadVideo(QString url) {
247 |
248 | if (url == "error_url" || url.isEmpty()) {
249 | win.setPlayerHtml();
250 | utils.addToLog("Error: provided url is incorrect.");
251 | utils.currentVideoUrl = "";
252 | return;
253 | }
254 |
255 | killProcesses();
256 | pathChanged = false;
257 | win.setVideoDetails(url);
258 | addToLog("Loaded video:
" + win.ui->urlEdit->text());
259 |
260 | }
261 |
262 | void Utilities::configInit() {
263 | configSetValueIfBlank("remove_sound", "false");
264 | configSetValueIfBlank("dont_convert", "false");
265 | configSetValueIfBlank("remove_raw", "true");
266 | configSetValueIfBlank("default_path", "");
267 | configSetValueIfBlank("open_output", "false");
268 | configSetValueIfBlank("show_ytdl_log", "true");
269 | configSetValueIfBlank("show_ffmpeg_log", "true");
270 | configSetValueIfBlank("youtubedl_path", "");
271 | configSetValueIfBlank("ffmpeg_path", "");
272 | configSetValueIfBlank("ffmpeg_params", "");
273 | configSetValueIfBlank("light_mode", "false");
274 | configSetValue("version", VERSION);
275 | }
276 |
277 | void Utilities::configSaveAll() {
278 | settings.setValue("remove_sound", win.ui->menuRemoveAudio->isChecked());
279 | settings.setValue("dont_convert", win.ui->menuDontConvert->isChecked());
280 | settings.setValue("remove_raw", win.ui->menuRemoveRawVideo->isChecked());
281 | settings.setValue("open_output", win.ui->menuShowFile->isChecked());
282 | settings.setValue("show_ytdl_log", win.ui->menuYoutubedlOutput->isChecked());
283 | settings.setValue("show_ffmpeg_log", win.ui->menuFfmpegOutput->isChecked());
284 | }
285 |
286 | void Utilities::configLoadAll() {
287 | win.ui->menuRemoveAudio->setChecked(configGetValueBool("remove_sound"));
288 | win.ui->menuDontConvert->setChecked(configGetValueBool("dont_convert"));
289 | win.ui->menuRemoveRawVideo->setChecked(configGetValueBool("remove_raw"));
290 | win.ui->menuShowFile->setChecked(configGetValueBool("open_output"));
291 | win.ui->menuYoutubedlOutput->setChecked(configGetValueBool("show_ytdl_log"));
292 | win.ui->menuFfmpegOutput->setChecked(configGetValueBool("show_ffmpeg_log"));
293 | }
294 |
295 | void Utilities::configSetValue(QString k, QString v) {
296 | settings.setValue(k, v);
297 | }
298 |
299 | void Utilities::configSetValueIfBlank(QString k, QString v) {
300 | if (!settings.contains(k))
301 | settings.setValue(k, v);
302 | }
303 |
304 | QString Utilities::configGetValue(QString k) {
305 | return settings.value(k).toString();
306 | }
307 |
308 | bool Utilities::configGetValueBool(QString k) {
309 | return settings.value(k).toBool();
310 | }
311 |
312 | void Utilities::removeRawVideo() {
313 | QFile::remove(getCurrentRawFilename());
314 | }
315 |
316 | void Utilities::showFileInDirectory() {
317 | QDesktopServices::openUrl("file:///" + QFileInfo(getCurrentFilename()).absolutePath());
318 | }
319 |
320 | void Utilities::updateBitrate() {
321 | if (!win.ui->cutFromEdit->text().trimmed().isEmpty() && !win.ui->cutToEdit->text().trimmed().isEmpty()) {
322 | int bitrate = win.ui->bitrateValue->text().toInt();
323 | bitrate = bitrate*utils.getTrimmedVideoDuration()/8;
324 | if (bitrate <= 0) {
325 | win.ui->estSize->setText("");
326 | return;
327 | }
328 | win.ui->estSize->setText(QString::number(float(bitrate)/1000) + " MB");
329 | }
330 | }
331 |
--------------------------------------------------------------------------------
/src/utilities.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILITIES_H
2 | #define UTILITIES_H
3 |
4 | #include "mainwindow.h"
5 | #include "downloader.h"
6 | #include "converter.h"
7 |
8 | #include
9 | #include
10 | #include
11 |
12 | #ifdef _WIN32
13 | #define SYSTEM 0
14 | #elif __APPLE__
15 | #define SYSTEM 1
16 | #else
17 | #define SYSTEM 2
18 | #endif
19 |
20 | class Utilities : public QObject
21 | {
22 | Q_OBJECT
23 |
24 | public:
25 | Utilities();
26 |
27 | QSettings settings;
28 |
29 | QString getBinaryName();
30 | QString getVideoQuality();
31 | QString getFileName();
32 | QString ffmpegBinaryName();
33 | QString getCurrentRawFilename();
34 | QString getCurrentFilename();
35 | QString getDefaultFilename();
36 |
37 | bool checkUrl();
38 | void setCommons();
39 | void startConversionProcess();
40 | void killProcesses();
41 | void addToLog(QString line, bool display = true);
42 | void removeRawVideo();
43 | void configInit();
44 | void configSetValue(QString k, QString v);
45 | void configSetValueIfBlank(QString k, QString v);
46 | void showFileInDirectory();
47 | void configSaveAll();
48 | void configLoadAll();
49 | void loadVideo(QString url);
50 | void updateBitrate();
51 | void startProcessQueue(QString url);
52 | void newVideo();
53 |
54 | QString configGetValue(QString k);
55 | bool configGetValueBool(QString k);
56 |
57 | int getTrimmedVideoDuration();
58 | QTime parseTime(QString s);
59 |
60 | int currentDuration;
61 | bool pathChanged;
62 | bool killed;
63 |
64 | QString defaultFilename;
65 | QString currentID;
66 | QString currentTitle;
67 | QString currentVideoUrl;
68 | QString currentSavePath;
69 | QString currentFileName;
70 | QString log;
71 |
72 | QVector > createQualityList(QString formats);
73 | QVector > currentQualityList;
74 |
75 | QProcess *downloadProcess;
76 | QProcess *conversionProcess;
77 | QProcess *processQueue;
78 |
79 | QStringList cmdsProcessQueue;
80 |
81 | Downloader download;
82 | Converter convert;
83 |
84 | private slots:
85 | void readProcessQueue();
86 | void nextProcessQueue(int c);
87 | void errorProcessQueue();
88 |
89 | };
90 |
91 | extern Utilities utils;
92 |
93 | #endif // UTILITIES_H
94 |
--------------------------------------------------------------------------------
/src/window.cpp:
--------------------------------------------------------------------------------
1 | #include "ui_mainwindow.h"
2 | #include "utilities.h"
3 | #include "window.h"
4 |
5 | #include
6 | #include
7 |
8 | Window win;
9 |
10 | Window::Window() {
11 | }
12 |
13 | void Window::setTheme() {
14 | qApp->setStyle(QStyleFactory::create("Fusion"));
15 | QPalette p = qApp->palette();
16 | p.setColor(QPalette::Window, QColor("#333"));
17 | p.setColor(QPalette::Button, QColor("#333"));
18 | p.setColor(QPalette::Highlight, QColor("#b31217"));
19 | p.setColor(QPalette::ButtonText, QColor("#888"));
20 | p.setColor(QPalette::WindowText, QColor("#888"));
21 | p.setColor(QPalette::Dark, QColor("#333"));
22 | p.setColor(QPalette::Light, QColor("#333"));
23 | qApp->setPalette(p);
24 | setStylesheet();
25 | }
26 |
27 | void Window::setStylesheet() {
28 | const char *css =
29 | "QPushButton:hover{background:#7d1cb4;}"
30 | "QWebView{background:#333;} QPlainTextEdit{background:#333;}"
31 | "QLineEdit{background:#888;border:none;height:35px;padding-left:10px;padding-right:10px;color:#222;}"
32 | "QProgressBar{background:#888; border:none;height:35px;color:#333;}"
33 | "QProgressBar::chunk{background:#b31217;}"
34 | "QPlainTextEdit{color:#888;}"
35 | "QComboBox{height:35px;border:none;background:#888;color:#333;}"
36 | "QComboBox::drop-down{border:none;background:#222;}"
37 | "QComboBox::drop-down::pressed{background:#b31217;}"
38 | "QComboBox QAbstractItemView{padding:15px;background:#888;}"
39 | "QMenu {background:#333;}"
40 | "QMenu::item{}"
41 | "QMenu::item::selected{background:#b31217;}"
42 | "QPushButton{border:none;background-color:#888;padding:25px;color:#333;}"
43 | "QPushButton::hover{background:#b31217;}"
44 | "QMessageBox{background:#222;}"
45 | "QToolButton{background:#222;border:none;width:35px;height:35px;}"
46 | "QToolButton:hover{background:#b31217;}"
47 | "#logBox{background:#333;border: 1px solid #3a3a3a;}"
48 | "QSpinBox{background:#888;border:none;height:35px;}";
49 |
50 | qApp->setStyleSheet(css);
51 | }
52 |
53 | bool Window::isModeLight() {
54 | if (win.ui->player == NULL)
55 | return true;
56 | return false;
57 | }
58 |
59 | void Window::setPlayerHtml() {
60 | if (isModeLight()) {
61 | return;
62 | }
63 |
64 | const char *html =
65 | ""
67 | "";
68 |
69 | win.ui->player->setHtml(html);
70 | }
71 |
72 | void Window::setLoaderHtml() {
73 | if (isModeLight()) {
74 | return;
75 | }
76 |
77 | const char *html =
78 | ""
80 | "";
81 |
82 | win.ui->player->setHtml(html);
83 | }
84 |
85 | void Window::setQualityList() {
86 | win.ui->qualityComboBox->blockSignals(true);
87 | for (int i=0; i < utils.currentQualityList.size(); i++)
88 | win.ui->qualityComboBox->addItem(utils.currentQualityList[i][0]);
89 | win.ui->qualityComboBox->blockSignals(false);
90 | }
91 |
92 | void Window::setVideoDetails(QString url) {
93 | reset();
94 | openUrlInPlayer(url);
95 | ui->titleEdit->setText(utils.currentTitle);
96 | setQualityList();
97 | utils.currentFileName = utils.getDefaultFilename();
98 | setFilename();
99 | win.lockAllControls(false);
100 | }
101 |
102 | void Window::openUrlInPlayer(QString url) {
103 | if (isModeLight())
104 | return;
105 |
106 | if (url.contains("youtu")) {
107 | win.ui->player->load("https://www.youtube.com/embed/" + utils.currentID);
108 | }
109 | else
110 | win.ui->player->load(url);
111 | }
112 |
113 | void Window::reset() {
114 | win.resetProgress();
115 | win.ui->filenameEdit->clear();
116 | win.ui->cutFromEdit->clear();
117 | win.ui->cutToEdit->clear();
118 | win.ui->qualityComboBox->blockSignals(true);
119 | win.ui->qualityComboBox->clear();
120 | win.ui->qualityComboBox->blockSignals(false);
121 | win.ui->bitrateValue->clear();
122 | win.ui->estSize->clear();
123 | }
124 |
125 | void Window::resetProgress() {
126 | win.ui->downloadProgressBar->setValue(0);
127 | win.ui->conversionProgressBar->setValue(0);
128 | }
129 |
130 | void Window::lockAllControls(bool status) {
131 | win.ui->cutFromEdit->setDisabled(status);
132 | win.ui->cutToEdit->setDisabled(status);
133 | win.ui->selectSavePath->setDisabled(status);
134 | win.ui->startConversion->setDisabled(status);
135 | win.ui->bitrateValue->setDisabled(status);
136 | }
137 |
138 | void Window::setFilename() {
139 | win.ui->filenameEdit->setText(utils.getCurrentFilename());
140 | }
141 |
142 | void Window::updateConversionButton() {
143 | QIcon icon;
144 | if (ui->startConversion->isChecked()) {
145 | icon = QIcon(":/icons/cancel.png");
146 | } else {
147 | icon = QIcon(":/icons/convert.png");
148 | }
149 | ui->startConversion->setIcon(icon);
150 | }
151 |
152 | void Window::toggleConversionButton() {
153 | ui->startConversion->toggle();
154 | updateConversionButton();
155 | }
156 |
157 | void Window::setLightMode(MainWindow *mw) {
158 | win.ui->player->deleteLater();
159 | win.ui->player = NULL;
160 | win.ui->horizontalLayout_3->setDirection(QBoxLayout::TopToBottom);
161 | win.ui->frame_2->setMaximumWidth(QWIDGETSIZE_MAX);
162 | mw->setMinimumWidth(300);
163 | mw->setMaximumWidth(300);
164 | mw->setMaximumWidth(QWIDGETSIZE_MAX);
165 | mw->move(QApplication::desktop()->screen()->rect().center() - mw->rect().center());
166 | }
167 |
168 | void Window::detectMode(MainWindow *mw) {
169 | if (utils.configGetValueBool("light_mode")) {
170 | win.ui->menuLtMode->setChecked(true);
171 | setLightMode(mw);
172 | } else {
173 | win.ui->menuLtMode->setChecked(false);
174 | }
175 | }
176 |
--------------------------------------------------------------------------------
/src/window.h:
--------------------------------------------------------------------------------
1 | #ifndef WINDOW_H
2 | #define WINDOW_H
3 |
4 | #include "mainwindow.h"
5 |
6 | class Window
7 | {
8 | public:
9 | Window();
10 | Ui::MainWindow *ui;
11 |
12 | void setQualityList();
13 | void setVideoDetails(QString url);
14 | void reset();
15 | void resetProgress();
16 | void setFilename();
17 | void lockAllControls(bool status);
18 | void setTheme();
19 | void setStylesheet();
20 | void updateConversionButton();
21 | void toggleConversionButton();
22 | void setPlayerHtml();
23 | void setLoaderHtml();
24 | void openUrlInPlayer(QString url);
25 | void setLightMode(MainWindow *mw);
26 | void detectMode(MainWindow *mw);
27 | bool isModeLight();
28 | };
29 |
30 | extern Window win;
31 |
32 | #endif // WINDOW_H
33 |
--------------------------------------------------------------------------------
/web-to-webm.pro:
--------------------------------------------------------------------------------
1 | #-------------------------------------------------
2 | #
3 | # Project created by QtCreator 2015-01-14T09:00:32
4 | #
5 | #-------------------------------------------------
6 |
7 | QT += core gui
8 | QT += webkit webkitwidgets
9 |
10 | greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
11 |
12 | VERSION = 0.7.2
13 |
14 | TARGET = web-to-webm
15 | TEMPLATE = app
16 |
17 | SOURCES += src/main.cpp\
18 | src/mainwindow.cpp \
19 | src/utilities.cpp \
20 | src/downloader.cpp \
21 | src/converter.cpp \
22 | src/window.cpp \
23 | src/updater.cpp
24 |
25 | HEADERS += src/mainwindow.h \
26 | src/utilities.h \
27 | src/downloader.h \
28 | src/converter.h \
29 | src/window.h \
30 | src/updater.h
31 |
32 | FORMS += src/mainwindow.ui \
33 | src/updater.ui
34 |
35 | DEFINES += VERSION=\\\"$$VERSION\\\"
36 |
37 | win32 {
38 | CONFIG(debug, debug|release) {
39 | renamer.commands = $(CXX) $$PWD/src/renamer.cpp && move renamer.exe debug\renamer.exe
40 | } else {
41 | renamer.commands = $(CXX) $$PWD/src/renamer.cpp && move renamer.exe release\renamer.exe
42 | }
43 | }
44 | unix:!macx {
45 | renamer.commands = $(CXX) $$PWD/src/renamer.cpp -o $$OUT_PWD/$(dir $(TARGET))renamer
46 | }
47 | macx {
48 | renamer.commands = mkdir -p $$OUT_PWD/$(dir $(TARGET)) && $(CXX) $$PWD/src/renamer.cpp -o $$OUT_PWD/$(dir $(TARGET))renamer
49 | }
50 |
51 |
52 | QMAKE_EXTRA_TARGETS += renamer
53 | POST_TARGETDEPS += renamer
54 |
55 | ICON = $${PWD}/resources/icons/web-to-webm.icns
56 | RC_FILE = $${PWD}/resources/web-to-webm.rc
57 |
58 | RESOURCES += \
59 | resources/Resources.qrc
60 |
--------------------------------------------------------------------------------