Compare commits
20 Commits
Author | SHA1 | Date |
---|---|---|
Martchus | 3e243750a0 | |
Martchus | ec0dda2677 | |
Martchus | 55deda90ff | |
Martchus | 7db4e0bc56 | |
Martchus | e4c5b23546 | |
Martchus | 5e42ba07ca | |
Martchus | 884bed480d | |
Martchus | 8d09b4e308 | |
Martchus | 82f15071b7 | |
Martchus | 6d5ca6e11c | |
Martchus | 07c7ec08b1 | |
Marius Kittler | 1ac4d7511d | |
Martchus | 29a80c029b | |
Martchus | 94a87052b0 | |
Martchus | 9b981dbeb9 | |
Martchus | d55642a43d | |
Martchus | cca4c0f567 | |
Martchus | eee967e21d | |
Marius Kittler | df12b96e29 | |
Marius Kittler | f1422c6d95 |
|
@ -1,4 +1,4 @@
|
|||
cmake_minimum_required(VERSION 3.1.0 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.17.0 FATAL_ERROR)
|
||||
|
||||
# meta data
|
||||
project(videodownloader)
|
||||
|
@ -8,10 +8,10 @@ set(META_APP_NAME "Video Downloader")
|
|||
set(META_APP_CATEGORIES "Network;FileTransfer")
|
||||
set(META_APP_AUTHOR "Martchus")
|
||||
set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
|
||||
set(META_APP_DESCRIPTION "Simple video downloader with Qt GUI (currently only YouTube and Vimeo are maintained)")
|
||||
set(META_APP_DESCRIPTION "Simple video downloader with Qt GUI and backends for multiple platforms, e.g. YouTube and Vimeo")
|
||||
set(META_VERSION_MAJOR 1)
|
||||
set(META_VERSION_MINOR 3)
|
||||
set(META_VERSION_PATCH 4)
|
||||
set(META_VERSION_PATCH 7)
|
||||
|
||||
# add project files
|
||||
set(HEADER_FILES
|
||||
|
@ -37,7 +37,6 @@ set(HEADER_FILES
|
|||
network/optiondata.h
|
||||
network/permissionstatus.h
|
||||
network/socksharedownload.h
|
||||
network/spotifydownload.h
|
||||
network/testdownload.h
|
||||
network/vimeodownload.h
|
||||
network/youtubedownload.h
|
||||
|
@ -63,7 +62,6 @@ set(SRC_FILES
|
|||
network/misc/contentdispositionparser.cpp
|
||||
network/optiondata.cpp
|
||||
network/socksharedownload.cpp
|
||||
network/spotifydownload.cpp
|
||||
network/testdownload.cpp
|
||||
network/vimeodownload.cpp
|
||||
network/youtubedownload.cpp
|
||||
|
@ -105,16 +103,6 @@ set(WIDGETS_UI_FILES
|
|||
gui/useragentpage.ui
|
||||
)
|
||||
|
||||
#set(QUICK_HEADER_FILES
|
||||
#)
|
||||
#set(QUICK_SRC_FILES
|
||||
#)
|
||||
|
||||
#set(TS_FILES
|
||||
# translations/${META_PROJECT_NAME}_de_DE.ts
|
||||
# translations/${META_PROJECT_NAME}_en_US.ts
|
||||
#)
|
||||
|
||||
set(ICON_FILES
|
||||
resources/icons/hicolor/scalable/apps/${META_PROJECT_NAME}.svg
|
||||
)
|
||||
|
@ -158,7 +146,7 @@ find_package(c++utilities${CONFIGURATION_PACKAGE_SUFFIX} 5.0.0 REQUIRED)
|
|||
use_cpp_utilities()
|
||||
|
||||
# find qtutilities
|
||||
find_package(qtutilities${CONFIGURATION_PACKAGE_SUFFIX} 6.0.0 REQUIRED)
|
||||
find_package(qtutilities${CONFIGURATION_PACKAGE_SUFFIX} 6.3.0 REQUIRED)
|
||||
use_qt_utilities()
|
||||
|
||||
# add Qt modules which can currently not be detected automatically
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
Files: resources/icons/*
|
||||
resources/icons/*
|
||||
|
||||
This subset of The Breeze Icon Theme is
|
||||
|
||||
Copyright (C) 2014 Uri Herrera <uri_herrera@nitrux.in> and others
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 3 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Clarification:
|
||||
|
||||
The GNU Lesser General Public License or LGPL is written for
|
||||
software libraries in the first place. We expressly want the LGPL to
|
||||
be valid for this artwork library too.
|
||||
|
||||
KDE Breeze theme icons is a special kind of software library, it is an
|
||||
artwork library, it's elements can be used in a Graphical User Interface, or
|
||||
GUI.
|
||||
|
||||
Source code, for this library means:
|
||||
- where they exist, SVG;
|
||||
- otherwise, if applicable, the multi-layered formats xcf or psd, or
|
||||
otherwise png.
|
||||
|
||||
The LGPL in some sections obliges you to make the files carry
|
||||
notices. With images this is in some cases impossible or hardly useful.
|
||||
|
||||
With this library a notice is placed at a prominent place in the directory
|
||||
containing the elements. You may follow this practice.
|
||||
|
||||
The exception in section 5 of the GNU Lesser General Public License covers
|
||||
the use of elements of this art library in a GUI.
|
||||
|
||||
https://vdesign.kde.org/
|
||||
|
||||
-----
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
35
README.md
|
@ -1,7 +1,14 @@
|
|||
# Video Downloader
|
||||
A video downloader with Qt 5 GUI.
|
||||
A video downloader with Qt GUI and backends for multiple platforms, e.g. YouTube and
|
||||
Vimeo.
|
||||
|
||||
Currently YouTube and Vimeo are the only maintained platforms.
|
||||
---
|
||||
|
||||
**Note**: This project is not maintained anymore so any provider-specific code might be
|
||||
outdated and not work anymore. I keep the project around as an example for doing HTTP
|
||||
downloads with Qt showing the progress and speed in a list view.
|
||||
|
||||
---
|
||||
|
||||
This is just a downloader. It does not convert or mux anything. You might use
|
||||
ffmpeg or mkvmerge to convert/remux downloaded videos.
|
||||
|
@ -14,18 +21,16 @@ The downloader allows to download any quality, including the HD qualities. Howev
|
|||
1080p streams (and above) are only provided as video-only or audio-only stream
|
||||
by YouTube which currently need to be downloaded separately and then muxed together.
|
||||
|
||||
## TODO
|
||||
* Fix (or remove) platforms that are not working.
|
||||
* Mux video-only and audio-only streams.
|
||||
* Command line interface
|
||||
* Fix issues with some YouTube videos
|
||||
|
||||
## Download / binary repository
|
||||
I currently provide packages for Arch Linux and Windows. Sources for those packages can be found in a
|
||||
separate [repository](https://github.com/Martchus/PKGBUILDs). For binaries checkout my
|
||||
[website](http://martchus.no-ip.biz/website/page.php?name=programming).
|
||||
|
||||
## Build instructions
|
||||
The video downloader depends on c++utilities and qtutilities and is built in the same way as these libaries.
|
||||
The video downloader depends on c++utilities and qtutilities and is built in the same
|
||||
way as these libraries.
|
||||
|
||||
The following Qt 5 modules are requried: core gui widgets network
|
||||
The following Qt modules are required: core gui widgets network
|
||||
|
||||
## Copyright notice and license
|
||||
Copyright © 2015-2022 Marius Kittler
|
||||
|
||||
All code is licensed under [GPL-2-or-later](LICENSE).
|
||||
|
||||
## Attribution for 3rd party content
|
||||
All icons found in this repository are taken from the [KDE/Breeze](https://invent.kde.org/frameworks/breeze-icons) project.
|
||||
|
|
|
@ -35,7 +35,7 @@ void replaceHtmlEntities(QString &text)
|
|||
QTextDocument textDocument;
|
||||
textDocument.setHtml(text);
|
||||
text = textDocument.toPlainText();
|
||||
foreach (const QChar &c, text) {
|
||||
for (const QChar &c : text) {
|
||||
if (!c.isSpace()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -74,7 +74,7 @@ void CliDownloadInteraction::downloadHasSslErrors(Download *download, size_t opt
|
|||
// TODO
|
||||
const string downloadName = (download->downloadUrl().isEmpty() ? download->id() : download->downloadUrl().toString()).toStdString();
|
||||
cout << "The download \"" << downloadName << "\" has SSL errors:" << endl;
|
||||
foreach (const QSslError &error, sslErrors) {
|
||||
for (const QSslError &error : sslErrors) {
|
||||
cout << "- " << error.errorString().toStdString() << ":" << endl;
|
||||
cout << " " << error.certificate().toText().toStdString() << endl;
|
||||
}
|
||||
|
|
|
@ -19,11 +19,11 @@ class CliDownloadInteraction : public QObject {
|
|||
public:
|
||||
explicit CliDownloadInteraction(QObject *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void connectDownload(Network::Download *download);
|
||||
void disconnectDownload(Network::Download *download);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadRequiresOutputDevice(Network::Download *download, size_t optionIndex);
|
||||
void downloadRequiresOutputDevice(Network::Download *download, size_t optionIndex, bool forceFileDialog);
|
||||
void downloadRequriesOverwritePermission(Network::Download *download, size_t optionIndex, const QString &file);
|
||||
|
|
|
@ -99,7 +99,7 @@ void download(int argc, char *argv[], const ArgumentOccurrence &, const Argument
|
|||
}
|
||||
++specifiedDownloads;
|
||||
}
|
||||
// check whether downloads could be instantiated, print appropiate error messages if not
|
||||
// check whether downloads could be instantiated, print appropriate error messages if not
|
||||
if (!specifiedDownloads) {
|
||||
cout << "No downloads have been specified." << endl;
|
||||
} else if (downloads.isEmpty()) {
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
#include "../network/socksharedownload.h"
|
||||
#include "../network/vimeodownload.h"
|
||||
#include "../network/youtubedownload.h"
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
#include "../network/spotifydownload.h"
|
||||
#endif
|
||||
|
||||
#include "ui_adddownloaddialog.h"
|
||||
|
||||
|
@ -24,13 +21,7 @@ using namespace Network;
|
|||
|
||||
namespace QtGui {
|
||||
|
||||
QStringList AddDownloadDialog::m_knownDownloadTypeNames = QStringList()
|
||||
<< QStringLiteral("standard http(s)/ftp") << QStringLiteral("Youtube") << QStringLiteral("Vimeo") << QStringLiteral("Grooveshark")
|
||||
<< QStringLiteral("Sockshare/Putlocker") << QStringLiteral("Bitshare") << QStringLiteral("FileNuke")
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
<< QStringLiteral("Spotify")
|
||||
#endif
|
||||
;
|
||||
QStringList AddDownloadDialog::s_knownDownloadTypeNames = QStringList();
|
||||
|
||||
AddDownloadDialog::AddDownloadDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
|
@ -40,6 +31,11 @@ AddDownloadDialog::AddDownloadDialog(QWidget *parent)
|
|||
, m_validInput(false)
|
||||
, m_selectDownloadTypeInputDialog(nullptr)
|
||||
{
|
||||
if (s_knownDownloadTypeNames.isEmpty()) {
|
||||
s_knownDownloadTypeNames << tr("Standard http(s)") << QStringLiteral("Youtube") << QStringLiteral("Vimeo") << QStringLiteral("Grooveshark")
|
||||
<< QStringLiteral("Sockshare/Putlocker") << QStringLiteral("Bitshare") << QStringLiteral("FileNuke");
|
||||
}
|
||||
|
||||
m_ui->setupUi(this);
|
||||
makeHeading(m_ui->mainInstructionLabel);
|
||||
setStyleSheet(dialogStyle());
|
||||
|
@ -89,10 +85,6 @@ Download *AddDownloadDialog::result() const
|
|||
return new BitshareDownload(QUrl(res));
|
||||
case 6:
|
||||
return new FileNukeDownload(QUrl(res));
|
||||
#ifdef UNDER_CONSTRUCTION
|
||||
case 7:
|
||||
return new SpotifyDownload(res);
|
||||
#endif
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -187,7 +179,7 @@ void AddDownloadDialog::textChanged(const QString &text)
|
|||
}
|
||||
if (m_downloadTypeIndex) {
|
||||
m_ui->downloadTypeLabel->setText(tr("The entered url seems to be from %1 so it will be added as %1 download.")
|
||||
.arg(m_knownDownloadTypeNames.at(m_downloadTypeIndex)));
|
||||
.arg(s_knownDownloadTypeNames.at(m_downloadTypeIndex)));
|
||||
} else {
|
||||
m_ui->downloadTypeLabel->setText(tr("The entered url will be added as standard %1 download.").arg(scheme));
|
||||
}
|
||||
|
@ -214,16 +206,16 @@ void AddDownloadDialog::adjustDetectedDownloadType()
|
|||
m_selectDownloadTypeInputDialog = new QInputDialog(this);
|
||||
m_selectDownloadTypeInputDialog->setWindowTitle(tr("Select download type"));
|
||||
m_selectDownloadTypeInputDialog->setLabelText(tr("Select as which kind of download the entered url should be treated."));
|
||||
m_selectDownloadTypeInputDialog->setComboBoxItems(m_knownDownloadTypeNames);
|
||||
m_selectDownloadTypeInputDialog->setComboBoxItems(s_knownDownloadTypeNames);
|
||||
m_selectDownloadTypeInputDialog->setComboBoxEditable(false);
|
||||
m_selectDownloadTypeInputDialog->setOption(QInputDialog::UseListViewForComboBoxItems);
|
||||
}
|
||||
|
||||
m_selectDownloadTypeInputDialog->setTextValue(m_knownDownloadTypeNames.at(m_downloadTypeIndex));
|
||||
m_selectDownloadTypeInputDialog->setTextValue(s_knownDownloadTypeNames.at(m_downloadTypeIndex));
|
||||
if (m_selectDownloadTypeInputDialog->exec()) {
|
||||
m_downloadTypeIndex = m_knownDownloadTypeNames.indexOf(m_selectDownloadTypeInputDialog->textValue());
|
||||
m_downloadTypeIndex = s_knownDownloadTypeNames.indexOf(m_selectDownloadTypeInputDialog->textValue());
|
||||
m_ui->downloadTypeLabel->setText(
|
||||
tr("The entered url will be added as %1 download (adjusted).").arg(m_knownDownloadTypeNames.at(m_downloadTypeIndex)));
|
||||
tr("The entered url will be added as %1 download (adjusted).").arg(s_knownDownloadTypeNames.at(m_downloadTypeIndex)));
|
||||
m_downloadTypeIndexAdjustedManually = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ public:
|
|||
void reset();
|
||||
bool hasValidInput() const;
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void addDownloadClicked();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void textChanged(const QString &text);
|
||||
void adjustDetectedDownloadType();
|
||||
void setLastUrl();
|
||||
|
@ -40,7 +40,7 @@ private slots:
|
|||
|
||||
private:
|
||||
std::unique_ptr<Ui::AddDownloadDialog> m_ui;
|
||||
static QStringList m_knownDownloadTypeNames;
|
||||
static QStringList s_knownDownloadTypeNames;
|
||||
int m_downloadTypeIndex;
|
||||
bool m_downloadTypeIndexAdjustedManually;
|
||||
bool m_validInput;
|
||||
|
|
|
@ -61,9 +61,6 @@
|
|||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>e. g. https://www.youtube.com/watch?v=YH1q_aUaW4w</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@ -76,8 +73,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-paste">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -130,7 +126,7 @@
|
|||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>adjust ...</string>
|
||||
<string>Adjust ...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -176,8 +172,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-previous">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -191,8 +186,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -104,13 +104,12 @@ void AddMultipleDownloadsEnterSearchTermPage::initializePage()
|
|||
if (AddMultipleDownloadsWizard *w = qobject_cast<AddMultipleDownloadsWizard *>(wizard())) {
|
||||
source = w->source();
|
||||
}
|
||||
// source = downloadSourceFromField(field(QStringLiteral("source"))); // does not work for some reason
|
||||
switch (source) {
|
||||
case DownloadSource::WebpageLinks:
|
||||
setTitle(tr("Specify the webpage"));
|
||||
setSubTitle(tr("Enter the URL."));
|
||||
setEnabled(true);
|
||||
m_searchTermLineEdit->setPlaceholderText(QStringLiteral("e. g. http://localhost"));
|
||||
m_searchTermLineEdit->setPlaceholderText(QStringLiteral("URL"));
|
||||
m_byIdCheckBox->setHidden(true);
|
||||
m_verifiedOnlyCheckBox->setHidden(true);
|
||||
break;
|
||||
|
@ -118,7 +117,7 @@ void AddMultipleDownloadsEnterSearchTermPage::initializePage()
|
|||
setTitle(tr("Specify YouTube playlist"));
|
||||
setSubTitle(tr("Enter the playlist URL or ID."));
|
||||
setEnabled(true);
|
||||
m_searchTermLineEdit->setPlaceholderText(QStringLiteral("e. g. https://www.youtube.com/playlist?list=PLg2u737x4TjfLFFEbEK9p77V2NRcLcTkr"));
|
||||
m_searchTermLineEdit->setPlaceholderText(QStringLiteral("URL"));
|
||||
m_byIdCheckBox->setHidden(false);
|
||||
m_verifiedOnlyCheckBox->setHidden(true);
|
||||
break;
|
||||
|
@ -253,7 +252,7 @@ QList<Download *> AddMultipleDownloadsResultsPage::results() const
|
|||
if (m_finder) {
|
||||
QModelIndexList selectedRows = m_view->selectionModel()->selectedRows();
|
||||
const QList<Download *> &allResults = m_finder->results();
|
||||
foreach (const QModelIndex &index, selectedRows) {
|
||||
for (const QModelIndex &index : selectedRows) {
|
||||
if (index.row() < allResults.size()) {
|
||||
results << allResults.at(index.row());
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
Network::DownloadFinder *finder() const;
|
||||
QList<Network::Download *> results() const;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void finderHasResults(const QList<Network::Download *> &newResults);
|
||||
void finderFinished(bool success, const QString &reason = QString());
|
||||
void selectionChanged(const QItemSelection &, const QItemSelection &);
|
||||
|
|
|
@ -59,7 +59,7 @@ void DownloadInteraction::downloadRequiresOutputDevice(Download *download, size_
|
|||
&& (TargetPage::targetDirectory().isEmpty() || QDir(TargetPage::targetDirectory()).exists()) // and the default directory exists or is empty
|
||||
&& !fileName.isEmpty()) { // and the file name is not empty
|
||||
download->provideOutputDevice(optionIndex, new QFile(TargetPage::targetDirectory() % QChar('/') % fileName), true);
|
||||
} else { // aks the user for the target path otherwise
|
||||
} else { // ask the user for the target path otherwise
|
||||
QFileDialog *dlg = new QFileDialog(m_parentWidget);
|
||||
#ifndef Q_OS_WIN
|
||||
// the native dialog can only be shown modal under Windows
|
||||
|
@ -215,7 +215,7 @@ void DownloadInteraction::downloadHasSslErrors(Download *download, size_t option
|
|||
{
|
||||
QString downloadName = download->downloadUrl().isEmpty() ? download->id() : download->downloadUrl().toString();
|
||||
QString details;
|
||||
foreach (const QSslError &error, sslErrors) {
|
||||
for (const QSslError &error : sslErrors) {
|
||||
if (!details.isEmpty()) {
|
||||
details.append(QStringLiteral("\n\n"));
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ void DownloadInteraction::downloadHasSslErrors(Download *download, size_t option
|
|||
}
|
||||
auto *dlg = new QMessageBox(m_parentWidget);
|
||||
dlg->setModal(false);
|
||||
dlg->setWindowTitle(tr("SSL errors occured") % QStringLiteral(" - ") % QCoreApplication::applicationName());
|
||||
dlg->setWindowTitle(tr("SSL errors occurred") % QStringLiteral(" - ") % QCoreApplication::applicationName());
|
||||
dlg->setTextFormat(Qt::RichText);
|
||||
dlg->setText(tr("The download <i>%1</i> has SSL errors.").arg(downloadName));
|
||||
dlg->setInformativeText(tr("Do you want to ignore the SSL errors for this download?"));
|
||||
|
|
|
@ -19,11 +19,11 @@ public:
|
|||
explicit DownloadInteraction(QObject *parent = nullptr);
|
||||
explicit DownloadInteraction(QWidget *parent = nullptr);
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
void connectDownload(Network::Download *download);
|
||||
void disconnectDownload(Network::Download *download);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadRequiresOutputDevice(Network::Download *download, size_t optionIndex);
|
||||
void downloadRequiresOutputDevice(Network::Download *download, size_t optionIndex, bool forceFileDialog);
|
||||
void downloadRequriesOverwritePermission(Network::Download *download, size_t optionIndex, const QString &file);
|
||||
|
|
|
@ -69,7 +69,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
, m_initiatingDownloads(0)
|
||||
, m_totalSpeed(0)
|
||||
, m_stillToReceive(0)
|
||||
, m_remainingTime(TimeSpan())
|
||||
, m_downloadInteraction(new DownloadInteraction(this))
|
||||
, m_addDownloadDlg(nullptr)
|
||||
, m_addMultipleDownloadsWizard(nullptr)
|
||||
|
@ -99,7 +98,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
action->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
|
||||
m_ui->menuAdd->addAction(action);
|
||||
#endif
|
||||
// Supervise clipboard tool button
|
||||
// add supervise clipboard tool button
|
||||
m_superviseClipboardToolButton = new QToolButton(m_ui->toolBar);
|
||||
m_superviseClipboardToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
|
||||
m_superviseClipboardToolButton->setText(tr("Supervise clipboard"));
|
||||
|
@ -114,7 +113,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
m_autoSpinBox->setMinimumSize(QSize(245, 0));
|
||||
m_autoSpinBox->setMaximum(10);
|
||||
m_autoSpinBox->setSuffix(tr(" download(s) automatically"));
|
||||
m_autoSpinBox->setPrefix(tr("start up to "));
|
||||
m_autoSpinBox->setPrefix(tr("Start up to "));
|
||||
QWidget *spacer = new QWidget(m_ui->autoToolBar);
|
||||
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
spacer->setVisible(true);
|
||||
|
@ -133,7 +132,6 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
// context menu
|
||||
m_downloadsTreeViewContextMenu = new QMenu(this);
|
||||
m_downloadsTreeViewContextMenu->addMenu(m_ui->menuAdd);
|
||||
m_ui->menuAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add")));
|
||||
m_downloadsTreeViewContextMenu->addAction(m_ui->actionStart_selected);
|
||||
m_downloadsTreeViewContextMenu->addAction(m_ui->actionResume_selected_downloads);
|
||||
m_downloadsTreeViewContextMenu->addAction(m_ui->actionRemove_selected_downloads_from_list);
|
||||
|
@ -160,18 +158,18 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
m_ui->statusBar->addWidget(m_downloadStatusLabel);
|
||||
m_elapsedTime.start();
|
||||
|
||||
// Connect signals and slots
|
||||
// Application
|
||||
// connect signals and slots
|
||||
// application
|
||||
connect(m_ui->actionSettings, &QAction::triggered, this, &MainWindow::showSettingsDialog);
|
||||
connect(m_ui->actionQuit, &QAction::triggered, &QApplication::quit);
|
||||
// Add
|
||||
// add
|
||||
connect(addDownloadToolButton, &QToolButton::clicked, this, &MainWindow::showAddDownloadDialog);
|
||||
connect(m_ui->actionAdd_Download, &QAction::triggered, this, &MainWindow::showAddDownloadDialog);
|
||||
connect(m_ui->actionAdd_multiple_downloads, &QAction::triggered, this, &MainWindow::showAddMultipleDownloadsDialog);
|
||||
#ifdef CONFIG_TESTDOWNLOAD
|
||||
connect(action, &QAction::triggered, [this] { this->addDownload(new TestDownload()); });
|
||||
#endif
|
||||
// Downloads
|
||||
// downloads
|
||||
connect(m_ui->actionStart_selected, &QAction::triggered, this, &MainWindow::startOrStopSelectedDownloads);
|
||||
connect(m_ui->actionResume_selected_downloads, &QAction::triggered, this, &MainWindow::interruptOrResumeSelectedDownloads);
|
||||
connect(m_ui->actionRemove_selected_downloads_from_list, &QAction::triggered, this, &MainWindow::removeSelectedDownloads);
|
||||
|
@ -197,7 +195,12 @@ MainWindow::~MainWindow()
|
|||
void MainWindow::showAboutDialog()
|
||||
{
|
||||
if (!m_aboutDlg) {
|
||||
m_aboutDlg = new AboutDialog(this, QStringLiteral(APP_URL), tr("A video downloader with Qt GUI (currently only YouTube is maintained)."),
|
||||
m_aboutDlg = new AboutDialog(this, QString(),
|
||||
QStringLiteral("<p>Developed by " APP_AUTHOR
|
||||
"<br>Program icon and fallback icons from <a href=\"https://invent.kde.org/frameworks/breeze-icons\">KDE/Breeze</a> "
|
||||
"project (copyright © 2014 Uri Herrera <uri_herrera@nitrux.in> and others, see the according "
|
||||
"<a href=\"" APP_URL "/blob/master/LICENSE.LESSER\">LGPL-3.0 license</a>)</p>"),
|
||||
QString(), QString(), tr("Simple video downloader with Qt GUI and backends for multiple platforms, e.g. YouTube and Vimeo."),
|
||||
QImage(QStringLiteral(":/icons/hicolor/128x128/apps/videodownloader.png")));
|
||||
}
|
||||
if (m_aboutDlg->isHidden()) {
|
||||
|
@ -268,7 +271,7 @@ void MainWindow::addMultipleDownloadsWizardResults()
|
|||
show();
|
||||
}
|
||||
if (m_addMultipleDownloadsWizard) {
|
||||
foreach (Download *res, m_addMultipleDownloadsWizard->results()) {
|
||||
for (Download *const res : m_addMultipleDownloadsWizard->results()) {
|
||||
addDownload(res);
|
||||
}
|
||||
m_addMultipleDownloadsWizard->restart();
|
||||
|
@ -332,7 +335,7 @@ void MainWindow::startOrStopSelectedDownloads()
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (Download *download, selectedDownloads) {
|
||||
for (Download *const download : selectedDownloads) {
|
||||
switch (download->status()) {
|
||||
case DownloadStatus::None:
|
||||
// retrieve initial information when that still has to be done
|
||||
|
@ -340,7 +343,7 @@ void MainWindow::startOrStopSelectedDownloads()
|
|||
download->init();
|
||||
break;
|
||||
case DownloadStatus::Initiating:
|
||||
// when the download is retireving initial information it can be stopped
|
||||
// when the download is retrieving initial information it can be stopped
|
||||
download->stop();
|
||||
break;
|
||||
case DownloadStatus::Downloading:
|
||||
|
@ -398,7 +401,7 @@ void MainWindow::interruptOrResumeSelectedDownloads()
|
|||
return;
|
||||
}
|
||||
|
||||
foreach (Download *download, selectedDownloads) {
|
||||
for (Download *const download : selectedDownloads) {
|
||||
switch (download->status()) {
|
||||
case DownloadStatus::Downloading:
|
||||
download->interrupt();
|
||||
|
@ -432,9 +435,10 @@ void MainWindow::removeSelectedDownloads()
|
|||
int removed = 0;
|
||||
QModelIndexList selectedIndexes = m_ui->downloadsTreeView->selectionModel()->selectedRows();
|
||||
QList<QPersistentModelIndex> persistendIndexes;
|
||||
foreach (QModelIndex selectedIndex, selectedIndexes)
|
||||
for (const QModelIndex &selectedIndex : selectedIndexes) {
|
||||
persistendIndexes << QPersistentModelIndex(selectedIndex);
|
||||
foreach (QPersistentModelIndex selectedIndex, persistendIndexes) {
|
||||
}
|
||||
for (const QPersistentModelIndex &selectedIndex : persistendIndexes) {
|
||||
if (Download *download = m_model->download(selectedIndex)) {
|
||||
switch (download->status()) {
|
||||
case DownloadStatus::Downloading:
|
||||
|
@ -474,15 +478,15 @@ void MainWindow::updateStartStopControls()
|
|||
int toInterrupt = 0;
|
||||
int noCommand = 0;
|
||||
int downloadLinksAvailable = 0;
|
||||
int removeable = 0;
|
||||
int removable = 0;
|
||||
int withTargetPath = 0;
|
||||
bool downloadsSelected = !selectedDownloads.isEmpty();
|
||||
if (downloadsSelected) {
|
||||
foreach (Download *download, selectedDownloads) {
|
||||
for (Download *const download : selectedDownloads) {
|
||||
switch (download->status()) {
|
||||
case DownloadStatus::None:
|
||||
++toInit;
|
||||
++removeable;
|
||||
++removable;
|
||||
break;
|
||||
case DownloadStatus::Initiating:
|
||||
++toStop;
|
||||
|
@ -497,7 +501,7 @@ void MainWindow::updateStartStopControls()
|
|||
break;
|
||||
case DownloadStatus::Ready:
|
||||
++downloadLinksAvailable;
|
||||
++removeable;
|
||||
++removable;
|
||||
if (download->supportsRange() && download->range().currentOffset() > 0) {
|
||||
++toResume;
|
||||
} else {
|
||||
|
@ -511,10 +515,10 @@ void MainWindow::updateStartStopControls()
|
|||
} else {
|
||||
++toInit;
|
||||
}
|
||||
++removeable;
|
||||
++removable;
|
||||
break;
|
||||
case DownloadStatus::Interrupted:
|
||||
++removeable;
|
||||
++removable;
|
||||
++downloadLinksAvailable;
|
||||
if (download->supportsRange()) {
|
||||
++toResume;
|
||||
|
@ -523,7 +527,7 @@ void MainWindow::updateStartStopControls()
|
|||
case DownloadStatus::Finished:
|
||||
++downloadLinksAvailable;
|
||||
++toRestart;
|
||||
++removeable;
|
||||
++removable;
|
||||
break;
|
||||
case DownloadStatus::Interrupting:
|
||||
case DownloadStatus::Aborting:
|
||||
|
@ -610,12 +614,12 @@ void MainWindow::updateStartStopControls()
|
|||
if (m_ui->toolBar->minimumWidth() < m_ui->toolBar->width()) {
|
||||
m_ui->toolBar->setMinimumWidth(m_ui->toolBar->width());
|
||||
}
|
||||
if (removeable == 1) {
|
||||
if (removable == 1) {
|
||||
m_ui->actionRemove_selected_downloads_from_list->setText(tr("Remove selected download from list"));
|
||||
} else if (removeable > 1) {
|
||||
m_ui->actionRemove_selected_downloads_from_list->setText(tr("Remove selected downloads (%1) from list").arg(removeable));
|
||||
} else if (removable > 1) {
|
||||
m_ui->actionRemove_selected_downloads_from_list->setText(tr("Remove selected downloads (%1) from list").arg(removable));
|
||||
}
|
||||
m_ui->actionRemove_selected_downloads_from_list->setEnabled(removeable > 0);
|
||||
m_ui->actionRemove_selected_downloads_from_list->setEnabled(removable > 0);
|
||||
if (downloadLinksAvailable > 0) {
|
||||
if (downloadLinksAvailable == 1) {
|
||||
m_ui->actionCopy_download_url->setText(tr("Copy download url"));
|
||||
|
@ -668,9 +672,9 @@ void MainWindow::clipboardDataChanged()
|
|||
{
|
||||
if (!m_internalClipboardChange && m_superviseClipboardToolButton->isChecked()) {
|
||||
QString data = QApplication::clipboard()->text();
|
||||
QStringList lines = data.split(QChar('\n'), QString::SkipEmptyParts);
|
||||
foreach (QString line, lines) {
|
||||
if (Download *download = Download::fromUrl(line)) {
|
||||
QStringList lines = data.split(QChar('\n'), Qt::SkipEmptyParts);
|
||||
for (const QString &line : lines) {
|
||||
if (Download *const download = Download::fromUrl(line)) {
|
||||
addDownload(download);
|
||||
if (m_trayIcon && m_trayIcon->isVisible()) {
|
||||
m_trayIcon->showMessage(windowTitle(), tr("The download \"%1\" has been added.").arg(data));
|
||||
|
@ -710,7 +714,7 @@ void MainWindow::setDownloadRange()
|
|||
} else if (!downloads.size()) {
|
||||
QMessageBox::warning(this, windowTitle(), tr("There is no download selected."));
|
||||
} else {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You can only set the range of a singe download at once."));
|
||||
QMessageBox::warning(this, windowTitle(), tr("You can only set the range of a single download at once."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,7 +730,7 @@ void MainWindow::setTargetPath()
|
|||
} else if (!downloads.size()) {
|
||||
QMessageBox::warning(this, windowTitle(), tr("There is no download selected."));
|
||||
} else {
|
||||
QMessageBox::warning(this, windowTitle(), tr("You can only set the target of a singe download at once."));
|
||||
QMessageBox::warning(this, windowTitle(), tr("You can only set the target of a single download at once."));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -734,7 +738,7 @@ void MainWindow::clearTargetPath()
|
|||
{
|
||||
QList<Download *> downloads = selectedDownloads();
|
||||
if (!downloads.isEmpty()) {
|
||||
foreach (Download *download, downloads) {
|
||||
for (Download *const download : downloads) {
|
||||
download->setTargetPath(QString());
|
||||
}
|
||||
updateStartStopControls();
|
||||
|
@ -745,7 +749,7 @@ void MainWindow::clearTargetPath()
|
|||
|
||||
void MainWindow::showYoutubeItagsInfo()
|
||||
{
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://en.wikipedia.org/wiki/YouTube#Quality_and_formats")));
|
||||
QDesktopServices::openUrl(QUrl(QStringLiteral("https://gist.github.com/sidneys/7095afe4da4ae58694d128b1034e01e2")));
|
||||
}
|
||||
|
||||
void MainWindow::resetGroovesharkSession()
|
||||
|
@ -883,7 +887,7 @@ QList<Download *> MainWindow::selectedDownloads() const
|
|||
{
|
||||
QList<Download *> res;
|
||||
QModelIndexList selectedRows = m_ui->downloadsTreeView->selectionModel()->selectedRows();
|
||||
foreach (QModelIndex index, selectedRows) {
|
||||
for (const QModelIndex &index : selectedRows) {
|
||||
if (Download *download = m_model->download(index)) {
|
||||
res << download;
|
||||
}
|
||||
|
@ -895,11 +899,7 @@ void MainWindow::setupTrayIcon()
|
|||
{
|
||||
#ifdef CONFIG_USE_TRAY_ICON
|
||||
if (!m_trayIcon) {
|
||||
#ifdef OS_WIN32
|
||||
m_trayIcon = new QSystemTrayIcon(QIcon(QStringLiteral(":/icons/hicolor/16x16/misc/trayicon.ico")));
|
||||
#else
|
||||
m_trayIcon = new QSystemTrayIcon(QIcon(QStringLiteral(":/icons/hicolor/128x128/apps/videodownloader.png")));
|
||||
#endif
|
||||
connect(m_trayIcon, &QSystemTrayIcon::activated, this,
|
||||
static_cast<void (MainWindow::*)(QSystemTrayIcon::ActivationReason)>(&MainWindow::trayIconActivated));
|
||||
}
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
|
||||
#include <c++utilities/chrono/timespan.h>
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QList>
|
||||
#include <QMainWindow>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTime>
|
||||
|
||||
#include <memory>
|
||||
|
||||
|
@ -49,7 +49,7 @@ public:
|
|||
protected:
|
||||
void closeEvent(QCloseEvent *);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadChangedStatus(Network::Download *download);
|
||||
void downloadChangedProgress(Network::Download *download);
|
||||
|
||||
|
@ -112,7 +112,7 @@ private:
|
|||
double m_totalSpeed;
|
||||
qint64 m_stillToReceive;
|
||||
CppUtilities::TimeSpan m_remainingTime;
|
||||
QTime m_elapsedTime;
|
||||
QElapsedTimer m_elapsedTime;
|
||||
DownloadInteraction *m_downloadInteraction;
|
||||
AddDownloadDialog *m_addDownloadDlg;
|
||||
AddMultipleDownloadsWizard *m_addMultipleDownloadsWizard;
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
<string>Video Downloader</string>
|
||||
</property>
|
||||
<property name="windowIcon">
|
||||
<iconset resource="../resources/icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/hicolor/32x32/categories/preferences-specific.png</normaloff>:/icons/hicolor/32x32/categories/preferences-specific.png</iconset>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
|
@ -43,7 +43,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>966</width>
|
||||
<height>27</height>
|
||||
<height>26</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="nativeMenuBar">
|
||||
|
@ -58,14 +58,14 @@
|
|||
</widget>
|
||||
<widget class="QMenu" name="menuAdd">
|
||||
<property name="title">
|
||||
<string>Add</string>
|
||||
<string>Add &download</string>
|
||||
</property>
|
||||
<addaction name="actionAdd_Download"/>
|
||||
<addaction name="actionAdd_multiple_downloads"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuDownloads">
|
||||
<property name="title">
|
||||
<string>Dow&nloads</string>
|
||||
<string>&Manage downloads</string>
|
||||
</property>
|
||||
<addaction name="actionStart_selected"/>
|
||||
<addaction name="actionResume_selected_downloads"/>
|
||||
|
@ -153,8 +153,7 @@
|
|||
<action name="actionAbout">
|
||||
<property name="icon">
|
||||
<iconset theme="help-about">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&About</string>
|
||||
|
@ -166,8 +165,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-start">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Start selected downloads</string>
|
||||
|
@ -179,8 +177,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-copy">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Copy download url</string>
|
||||
|
@ -188,7 +185,7 @@
|
|||
</action>
|
||||
<action name="actionYoutube_itags">
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/icons.qrc">
|
||||
<iconset>
|
||||
<normaloff>:/icons/hicolor/32x32/categories/preferences-specific.png</normaloff>:/icons/hicolor/32x32/categories/preferences-specific.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
|
@ -198,8 +195,7 @@
|
|||
<action name="actionAdd_multiple_downloads">
|
||||
<property name="icon">
|
||||
<iconset theme="list-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Multiple downloads</string>
|
||||
|
@ -217,8 +213,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-remove">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Remove selected downloads from list</string>
|
||||
|
@ -227,8 +222,7 @@
|
|||
<action name="actionExplore_target_directory">
|
||||
<property name="icon">
|
||||
<iconset theme="system-file-manager">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Explore target directory</string>
|
||||
|
@ -240,8 +234,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="media-playback-pause">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Interrupt selected downloads</string>
|
||||
|
@ -250,8 +243,7 @@
|
|||
<action name="actionReset_grooveshark_session">
|
||||
<property name="icon">
|
||||
<iconset theme="document-revert">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>R&eset Grooveshark session</string>
|
||||
|
@ -263,8 +255,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-cut">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set range &of selected download</string>
|
||||
|
@ -273,8 +264,7 @@
|
|||
<action name="actionAdd_Download">
|
||||
<property name="icon">
|
||||
<iconset theme="list-add">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Single download</string>
|
||||
|
@ -292,8 +282,7 @@
|
|||
<action name="actionSettings">
|
||||
<property name="icon">
|
||||
<iconset theme="preferences-other">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Settings</string>
|
||||
|
@ -305,8 +294,7 @@
|
|||
<action name="actionQuit">
|
||||
<property name="icon">
|
||||
<iconset theme="application-exit">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Quit</string>
|
||||
|
@ -318,8 +306,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-save-as">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Set target of selected &download</string>
|
||||
|
@ -331,8 +318,7 @@
|
|||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-undo">
|
||||
<normaloff/>
|
||||
</iconset>
|
||||
<normaloff>.</normaloff>.</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>C&lear target of selected downloads</string>
|
||||
|
@ -340,8 +326,6 @@
|
|||
</action>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<resources>
|
||||
<include location="../resources/icons.qrc"/>
|
||||
</resources>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -2,14 +2,6 @@
|
|||
<ui version="4.0">
|
||||
<class>QtGui::ProxyPage</class>
|
||||
<widget class="QWidget" name="QtGui::ProxyPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>245</width>
|
||||
<height>220</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Proxy</string>
|
||||
</property>
|
||||
|
|
|
@ -22,7 +22,7 @@ public:
|
|||
explicit SetRangeDialog(Network::DownloadRange &range, QWidget *parent = nullptr);
|
||||
~SetRangeDialog();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void confirm();
|
||||
|
||||
private:
|
||||
|
|
|
@ -171,7 +171,7 @@ QWidget *UiPage::setupWidget()
|
|||
mainWindowLabel->setStyleSheet(QStringLiteral("font-weight: bold;"));
|
||||
layout->addWidget(mainWindowLabel);
|
||||
layout->addWidget(
|
||||
m_multiSelectionCheckBox = new QCheckBox(QApplication::translate("QtGui::GeneralUiOptionPage", "enable multi-selection"), widget));
|
||||
m_multiSelectionCheckBox = new QCheckBox(QApplication::translate("QtGui::GeneralUiOptionPage", "Enable multi-selection"), widget));
|
||||
widget->setLayout(layout);
|
||||
return widget;
|
||||
}
|
||||
|
@ -256,7 +256,7 @@ QWidget *ProxyPage::setupWidget()
|
|||
|
||||
void ProxyPage::updateProxy()
|
||||
{
|
||||
QStringList parts = ui()->hostNameLineEdit->text().split(":", QString::SkipEmptyParts);
|
||||
QStringList parts = ui()->hostNameLineEdit->text().split(":", Qt::SkipEmptyParts);
|
||||
if (parts.count() == 2) {
|
||||
bool ok;
|
||||
int port = parts.at(1).toInt(&ok);
|
||||
|
@ -346,7 +346,7 @@ QWidget *MiscPage::setupWidget()
|
|||
widget->setWindowTitle(QApplication::translate("QtGui::NetworkMiscOptionPage", "Misc"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(widget);
|
||||
layout->addWidget(
|
||||
m_redirectCheckBox = new QCheckBox(QApplication::translate("QtGui::NetworkMiscOptionPage", "follow redirections without asking"), widget));
|
||||
m_redirectCheckBox = new QCheckBox(QApplication::translate("QtGui::NetworkMiscOptionPage", "Follow redirections without asking"), widget));
|
||||
widget->setLayout(layout);
|
||||
return widget;
|
||||
}
|
||||
|
@ -406,29 +406,23 @@ SettingsDialog::SettingsDialog(QWidget *parent)
|
|||
category->setDisplayName(tr("General"));
|
||||
category->assignPages({ new TargetPage(this), new UiPage() });
|
||||
category->setIcon(
|
||||
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-general.png"))));
|
||||
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-other.svg"))));
|
||||
categories << category;
|
||||
|
||||
category = new OptionCategory(this);
|
||||
category->setDisplayName(tr("Network"));
|
||||
category->setIcon(QIcon::fromTheme(
|
||||
QStringLiteral("preferences-system-network"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-network.png"))));
|
||||
QStringLiteral("preferences-system-network"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/applications-internet.svg"))));
|
||||
category->assignPages({ new ProxyPage(), new UserAgentPage(), new MiscPage(), new StatsPage() });
|
||||
categories << category;
|
||||
|
||||
category = new OptionCategory(this);
|
||||
category->setDisplayName(tr("Specific"));
|
||||
category->setIcon(QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-specific.png")));
|
||||
category->assignPages({});
|
||||
categories << category;
|
||||
|
||||
categories << qtSettings().category();
|
||||
|
||||
categoryModel()->setCategories(categories);
|
||||
|
||||
setMinimumSize(800, 450);
|
||||
setWindowIcon(
|
||||
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-general.png"))));
|
||||
QIcon::fromTheme(QStringLiteral("preferences-other"), QIcon(QStringLiteral(":/icons/hicolor/32x32/categories/preferences-other.svg"))));
|
||||
}
|
||||
|
||||
SettingsDialog::~SettingsDialog()
|
||||
|
|
|
@ -2,14 +2,6 @@
|
|||
<ui version="4.0">
|
||||
<class>QtGui::TargetPage</class>
|
||||
<widget class="QWidget" name="QtGui::TargetPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>331</width>
|
||||
<height>180</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Target directory</string>
|
||||
</property>
|
||||
|
@ -138,14 +130,14 @@
|
|||
<item>
|
||||
<widget class="QCheckBox" name="overwriteCheckBox">
|
||||
<property name="text">
|
||||
<string>don't ask before overwriting existing files</string>
|
||||
<string>Don't ask before overwriting existing files</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="askOnlyWhenThereIsNoAppropriateFilenameCheckBox">
|
||||
<property name="text">
|
||||
<string>ask only where to save files if there is no appropriate filename</string>
|
||||
<string>Ask only where to save files if there is no appropriate filename</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
|
|
|
@ -2,14 +2,6 @@
|
|||
<ui version="4.0">
|
||||
<class>QtGui::UserAgentPage</class>
|
||||
<widget class="QWidget" name="QtGui::UserAgentPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>239</width>
|
||||
<height>68</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>HTTP user agent</string>
|
||||
</property>
|
||||
|
|
|
@ -45,7 +45,7 @@ void DownloadFinderResultsModel::setFinder(DownloadFinder *finder)
|
|||
});
|
||||
// new results are available
|
||||
connect(m_finder, &DownloadFinder::newResultsAvailable, [this](const QList<Download *> &results) {
|
||||
foreach (Download *download, results) {
|
||||
for (Download *const download : results) {
|
||||
connect(download, &Download::statusChanged, this, &DownloadFinderResultsModel::downloadChangedStatus);
|
||||
// initiate the download if not done yet and instant initiation is recommendable
|
||||
if (!download->isInitiated() && download->isInitiatingInstantlyRecommendable()) {
|
||||
|
|
|
@ -34,7 +34,7 @@ public:
|
|||
static constexpr int idColumn();
|
||||
static constexpr int lastColumn();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadChangedStatus(Network::Download *download);
|
||||
|
||||
private:
|
||||
|
|
|
@ -43,7 +43,7 @@ public:
|
|||
static constexpr int progressColumn();
|
||||
static constexpr int lastColumn();
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadChangedStatus(Network::Download *download);
|
||||
void downloadProgressChanged(Network::Download *download);
|
||||
void downloadInfoChanged(Network::Download *download);
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace Network {
|
|||
* - reportNewDataToBeWritten(): Reports that there is new data to be written available.
|
||||
* - reportRedirectionAvailable(): Reports that there is a redirection available.
|
||||
* - reportAuthenticationRequired(): Reports that authentication credentials are required.
|
||||
* - reportSslErrors(): Reports that one or more SSL errors occured.
|
||||
* - reportSslErrors(): Reports that one or more SSL errors occurred.
|
||||
* - reportDownloadComplete(): Reports that the download is complete.
|
||||
* - reportFinalDownloadStatus(): Reports the final download status.
|
||||
* - addDownloadUrl(): Makes a download URL under the specified option name available. Meant to be called during initialization.
|
||||
|
@ -71,7 +71,7 @@ namespace Network {
|
|||
* using the provideAuthenticationCredentials() method.
|
||||
*/
|
||||
|
||||
int Download::m_defaultUserAgent = -1;
|
||||
int Download::s_defaultUserAgent = -1;
|
||||
|
||||
/*!
|
||||
* \brief Returns a random default user agent string.
|
||||
|
@ -91,10 +91,10 @@ const QString &Download::defaultUserAgent()
|
|||
QStringLiteral("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/37.0.2062.120 Safari/537.36"),
|
||||
QStringLiteral("Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) konqueror/4.14.0 Safari/534.34"),
|
||||
QStringLiteral("Opera/9.80 (Windows NT 6.0) Presto/2.12.388 Version/12.14") };
|
||||
if (m_defaultUserAgent < 0 || m_defaultUserAgent > 6) {
|
||||
if (s_defaultUserAgent < 0 || s_defaultUserAgent > 6) {
|
||||
scrambleDefaultUserAgent();
|
||||
}
|
||||
return agents[m_defaultUserAgent];
|
||||
return agents[s_defaultUserAgent];
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -106,7 +106,7 @@ void Download::scrambleDefaultUserAgent()
|
|||
random_device rd;
|
||||
default_random_engine engine(rd());
|
||||
uniform_int_distribution<int> distribution(0, 6);
|
||||
m_defaultUserAgent = distribution(engine);
|
||||
s_defaultUserAgent = distribution(engine);
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -350,7 +350,7 @@ void Download::interrupt()
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new donwload with the specified \a url.
|
||||
* \brief Constructs a new download with the specified \a url.
|
||||
*/
|
||||
Download::Download(const QUrl &url, QObject *parent)
|
||||
: QObject(parent)
|
||||
|
@ -369,9 +369,6 @@ Download::Download(const QUrl &url, QObject *parent)
|
|||
, m_newBytesToReceive(0)
|
||||
, m_speed(0.0)
|
||||
, m_shiftSpeed(0.0)
|
||||
, m_shiftRemainingTime(TimeSpan())
|
||||
, m_statusInfo(QString())
|
||||
, m_time(QTime())
|
||||
, m_networkError(QNetworkReply::NoError)
|
||||
, m_initiated(false)
|
||||
, m_progressUpdateInterval(300)
|
||||
|
@ -387,7 +384,7 @@ Download::Download(const QUrl &url, QObject *parent)
|
|||
*
|
||||
* Needs to be implemented when subclassing.
|
||||
*/
|
||||
bool Download::followRedirection(size_t)
|
||||
bool Download::followRedirection(std::size_t)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -432,11 +429,11 @@ void Download::init()
|
|||
/*!
|
||||
* \brief Reports the initialization status.
|
||||
*
|
||||
* Needs to be called when subclassing after the initialzation ended.
|
||||
* Needs to be called when subclassing after the initialization ended.
|
||||
*
|
||||
* \param success Specifies whether the initialization succeeded.
|
||||
* \param reasonIfNot Specifies the reason if the initialization failed; ignored otherwise.
|
||||
* \param networkError Specifies if and what kind of network error occured.
|
||||
* \param networkError Specifies if and what kind of network error occurred.
|
||||
*/
|
||||
void Download::reportInitiated(bool success, const QString &reasonIfNot, const QNetworkReply::NetworkError &networkError)
|
||||
{
|
||||
|
@ -615,7 +612,7 @@ void Download::finalizeOutputDevice(size_t optionIndex)
|
|||
* \param optionIndex Specifies the concerning option.
|
||||
* \param success Specifies whether the download was successful.
|
||||
* \param statusDescription Specifies a status description.
|
||||
* \param networkError Specifies if or what kind of network error occured.
|
||||
* \param networkError Specifies if or what kind of network error occurred.
|
||||
*/
|
||||
void Download::reportFinalDownloadStatus(size_t optionIndex, bool success, const QString &statusDescription, QNetworkReply::NetworkError networkError)
|
||||
{
|
||||
|
@ -805,7 +802,7 @@ void Download::reportRedirectionAvailable(size_t originalOptionIndex)
|
|||
optionData.m_downloadComplete = false;
|
||||
setStatus(DownloadStatus::Downloading);
|
||||
} else {
|
||||
reportFinalDownloadStatus(originalOptionIndex, false, tr("Follwing redirection failed."));
|
||||
reportFinalDownloadStatus(originalOptionIndex, false, tr("Following redirection failed."));
|
||||
}
|
||||
break;
|
||||
case PermissionStatus::Refused:
|
||||
|
@ -836,14 +833,14 @@ void Download::reportAuthenticationRequired(size_t optionIndex, const QString &r
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Reports that SSL errors occured.
|
||||
* \brief Reports that SSL errors occurred.
|
||||
*
|
||||
* \param optionIndex Specifies the concerning option index. Use a negative value when the
|
||||
* errors occured during initialization.
|
||||
* errors occurred during initialization.
|
||||
* \param reply Specifies the concerning reply.
|
||||
* \param sslErrors Specifies which SSL errors occured.
|
||||
* \param sslErrors Specifies which SSL errors occurred.
|
||||
*
|
||||
* Needs to be called when subclassing if SSL errors occured.
|
||||
* Needs to be called when subclassing if SSL errors occurred.
|
||||
*/
|
||||
void Download::reportSslErrors(size_t optionIndex, QNetworkReply *reply, const QList<QSslError> &sslErrors)
|
||||
{
|
||||
|
@ -943,7 +940,7 @@ void Download::changeDownloadUrl(size_t optionIndex, const QUrl &value)
|
|||
* \brief Provides an output device.
|
||||
* \param optionIndex Specifies the index of the option the output device is provided for.
|
||||
* \param device Specifies the output device.
|
||||
* \param giveOwnership Specifies whether the ownership is transfered to download.
|
||||
* \param giveOwnership Specifies whether the ownership is transferred to download.
|
||||
*
|
||||
* Use this method to provide an output device after the outputDeviceRequired() signal has
|
||||
* been emitted.
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
#include <QAuthenticator>
|
||||
#include <QBuffer>
|
||||
#include <QElapsedTimer>
|
||||
#include <QFile>
|
||||
#include <QNetworkProxy>
|
||||
#include <QNetworkReply>
|
||||
#include <QObject>
|
||||
#include <QTime>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
|
@ -40,7 +40,7 @@ class Download : public QObject {
|
|||
public:
|
||||
virtual ~Download();
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
// public slots to control the download
|
||||
void init();
|
||||
void start();
|
||||
|
@ -78,20 +78,20 @@ public:
|
|||
void setTargetPath(const QString &targetPath);
|
||||
const QUrl &initialUrl() const;
|
||||
const QUrl &downloadUrl() const;
|
||||
const QUrl &downloadUrl(size_t optionIndex) const;
|
||||
const QUrl &downloadUrl(std::size_t optionIndex) const;
|
||||
const std::vector<OptionData> &options() const;
|
||||
std::vector<OptionData> &options();
|
||||
const QString &id() const;
|
||||
const QString &title() const;
|
||||
const QString &collectionName() const;
|
||||
size_t availableOptionCount() const;
|
||||
std::size_t availableOptionCount() const;
|
||||
bool areOptionsAvailable() const;
|
||||
const QString &optionName(size_t optionIndex) const;
|
||||
const QString &optionName(std::size_t optionIndex) const;
|
||||
bool haveAvailableOptionsChanged();
|
||||
bool isValidOptionChosen() const;
|
||||
size_t chosenOption() const;
|
||||
std::size_t chosenOption() const;
|
||||
const QString &chosenOptionName() const;
|
||||
bool setChosenOption(size_t optionIndex);
|
||||
bool setChosenOption(std::size_t optionIndex);
|
||||
bool hasSelectedOptionChanged();
|
||||
const QString &userAgent();
|
||||
void setCustomUserAgent(const QString &value);
|
||||
|
@ -116,12 +116,12 @@ public:
|
|||
void provideMetaData(const QString &title = QString(), const QString &uploader = QString(),
|
||||
CppUtilities::TimeSpan duration = CppUtilities::TimeSpan(), const QString &collectionName = QString(), int positionInCollection = 0,
|
||||
int views = 0, const QString &rating = QString());
|
||||
void setOverwritePermission(size_t optionIndex, PermissionStatus permission);
|
||||
void setAppendPermission(size_t optionIndex, PermissionStatus permission);
|
||||
void setRedirectPermission(size_t originalOptionIndex, PermissionStatus permission);
|
||||
void setIgnoreSslErrorsPermission(size_t optionIndex, PermissionStatus permission);
|
||||
void provideOutputDevice(size_t optionIndex, QIODevice *device, bool giveOwnership = false);
|
||||
void provideAuthenticationCredentials(size_t optionIndex, const AuthenticationCredentials &credentials);
|
||||
void setOverwritePermission(std::size_t optionIndex, PermissionStatus permission);
|
||||
void setAppendPermission(std::size_t optionIndex, PermissionStatus permission);
|
||||
void setRedirectPermission(std::size_t originalOptionIndex, PermissionStatus permission);
|
||||
void setIgnoreSslErrorsPermission(std::size_t optionIndex, PermissionStatus permission);
|
||||
void provideOutputDevice(std::size_t optionIndex, QIODevice *device, bool giveOwnership = false);
|
||||
void provideAuthenticationCredentials(std::size_t optionIndex, const AuthenticationCredentials &credentials);
|
||||
const AuthenticationCredentials &initialAuthenticationCredentials() const;
|
||||
AuthenticationCredentials &initialAuthenticationCredentials();
|
||||
virtual bool isInitiatingInstantlyRecommendable() const;
|
||||
|
@ -129,16 +129,16 @@ public:
|
|||
// to construct new downloads
|
||||
static Download *fromUrl(const QUrl &url);
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void statusChanged(Download *download);
|
||||
void progressChanged(Download *download);
|
||||
void statusInfoChanged(Download *download);
|
||||
void overwriteingPermissionRequired(Download *download, size_t optionIndex, const QString &file);
|
||||
void appendingPermissionRequired(Download *download, size_t optionIndex, const QString &file, quint64 offset, quint64 fileSize);
|
||||
void redirectionPermissonRequired(Download *download, size_t optionIndex, int redirectionOptionIndex);
|
||||
void outputDeviceRequired(Download *concerningDownload, size_t optionIndex);
|
||||
void authenticationRequired(Download *concerningDownload, size_t optionIndex, const QString &statusInfo);
|
||||
void sslErrors(Download *concerningDownload, size_t optionIndex, const QList<QSslError> &sslErrors);
|
||||
void overwriteingPermissionRequired(Download *download, std::size_t optionIndex, const QString &file);
|
||||
void appendingPermissionRequired(Download *download, std::size_t optionIndex, const QString &file, quint64 offset, quint64 fileSize);
|
||||
void redirectionPermissonRequired(Download *download, std::size_t optionIndex, int redirectionOptionIndex);
|
||||
void outputDeviceRequired(Download *concerningDownload, std::size_t optionIndex);
|
||||
void authenticationRequired(Download *concerningDownload, std::size_t optionIndex, const QString &statusInfo);
|
||||
void sslErrors(Download *concerningDownload, std::size_t optionIndex, const QList<QSslError> &sslErrors);
|
||||
|
||||
protected:
|
||||
// c'tor
|
||||
|
@ -147,25 +147,25 @@ protected:
|
|||
// protected methods
|
||||
// to be implemented by derived classes
|
||||
virtual void doDownload() = 0;
|
||||
virtual bool followRedirection(size_t originalOptionIndex);
|
||||
virtual bool followRedirection(std::size_t originalOptionIndex);
|
||||
virtual void abortDownload() = 0;
|
||||
virtual void doInit() = 0;
|
||||
virtual void checkStatusAndClear(size_t optionIndex) = 0;
|
||||
virtual void checkStatusAndClear(std::size_t optionIndex) = 0;
|
||||
// meant to be called by derived classes
|
||||
size_t addDownloadUrl(const QString &optionName, const QUrl &url, size_t redirectionOf = InvalidOptionIndex);
|
||||
void changeDownloadUrl(size_t optionIndex, const QUrl &value);
|
||||
std::size_t addDownloadUrl(const QString &optionName, const QUrl &url, std::size_t redirectionOf = InvalidOptionIndex);
|
||||
void changeDownloadUrl(std::size_t optionIndex, const QUrl &value);
|
||||
void reportInitiated(
|
||||
bool success, const QString &reasonIfNot = QString(), const QNetworkReply::NetworkError &networkError = QNetworkReply::NoError);
|
||||
void reportFinalDownloadStatus(size_t optionIndex, bool success, const QString &statusDescription = QString(),
|
||||
void reportFinalDownloadStatus(std::size_t optionIndex, bool success, const QString &statusDescription = QString(),
|
||||
QNetworkReply::NetworkError networkError = QNetworkReply::NoError);
|
||||
protected slots:
|
||||
void reportDownloadInterrupted(size_t optionIndex);
|
||||
void reportNewDataToBeWritten(size_t optionIndex, QIODevice *inputDevice);
|
||||
void reportRedirectionAvailable(size_t originalOptionIndex);
|
||||
void reportAuthenticationRequired(size_t optionIndex, const QString &realm);
|
||||
void reportSslErrors(size_t optionIndex, QNetworkReply *reply, const QList<QSslError> &sslErrors);
|
||||
void reportDownloadComplete(size_t optionIndex);
|
||||
void finalizeOutputDevice(size_t optionIndex);
|
||||
protected Q_SLOTS:
|
||||
void reportDownloadInterrupted(std::size_t optionIndex);
|
||||
void reportNewDataToBeWritten(std::size_t optionIndex, QIODevice *inputDevice);
|
||||
void reportRedirectionAvailable(std::size_t originalOptionIndex);
|
||||
void reportAuthenticationRequired(std::size_t optionIndex, const QString &realm);
|
||||
void reportSslErrors(std::size_t optionIndex, QNetworkReply *reply, const QList<QSslError> &sslErrors);
|
||||
void reportDownloadComplete(std::size_t optionIndex);
|
||||
void finalizeOutputDevice(std::size_t optionIndex);
|
||||
void setId(const QString &value);
|
||||
void setTitle(const QString &value);
|
||||
void setTitleFromFilename(const QString &valueObtainedFromFilename);
|
||||
|
@ -175,7 +175,7 @@ protected slots:
|
|||
void setRating(const QString &value);
|
||||
void setPositionInCollection(int value);
|
||||
void setCollectionName(const QString &value);
|
||||
void reportDownloadProgressUpdate(size_t optionIndex, qint64 bytesReceived, qint64 bytesToReceive);
|
||||
void reportDownloadProgressUpdate(std::size_t optionIndex, qint64 bytesReceived, qint64 bytesToReceive);
|
||||
|
||||
private:
|
||||
// private static methods
|
||||
|
@ -184,9 +184,9 @@ private:
|
|||
|
||||
// private methods
|
||||
// to handle the output device
|
||||
bool writeBufferToOutputDevice(size_t optionIndex);
|
||||
bool prepareOutputDevice(size_t optionIndex, QIODevice *device, bool takeOwnership);
|
||||
void ensureOutputDeviceIsPrepared(size_t optionIndex);
|
||||
bool writeBufferToOutputDevice(std::size_t optionIndex);
|
||||
bool prepareOutputDevice(std::size_t optionIndex, QIODevice *device, bool takeOwnership);
|
||||
void ensureOutputDeviceIsPrepared(std::size_t optionIndex);
|
||||
// to set status information
|
||||
void setBytesWritten(qint64 value);
|
||||
void setProgress(qint64 m_bytesReceived = -1, qint64 m_bytesToReceive = -1);
|
||||
|
@ -211,7 +211,7 @@ private:
|
|||
|
||||
// concerning available options
|
||||
std::vector<OptionData> m_optionData;
|
||||
size_t m_chosenOption;
|
||||
std::size_t m_chosenOption;
|
||||
bool m_selectedOptionChanged;
|
||||
bool m_availableOptionsChanged;
|
||||
|
||||
|
@ -226,7 +226,7 @@ private:
|
|||
double m_shiftSpeed;
|
||||
CppUtilities::TimeSpan m_shiftRemainingTime;
|
||||
QString m_statusInfo;
|
||||
QTime m_time;
|
||||
QElapsedTimer m_time;
|
||||
QNetworkReply::NetworkError m_networkError;
|
||||
bool m_initiated;
|
||||
int m_progressUpdateInterval;
|
||||
|
@ -234,7 +234,7 @@ private:
|
|||
// concerning download
|
||||
bool m_useDefaultUserAgent;
|
||||
QString m_userAgent;
|
||||
static int m_defaultUserAgent;
|
||||
static int s_defaultUserAgent;
|
||||
QNetworkProxy m_proxy;
|
||||
QString m_targetPath;
|
||||
DownloadRange m_range;
|
||||
|
@ -287,7 +287,7 @@ inline const QUrl &Download::downloadUrl() const
|
|||
* - Some downloads might use additional information (for instance if the POST method is used).
|
||||
* - This information is possibly not available before the download is initiated.
|
||||
*/
|
||||
inline const QUrl &Download::downloadUrl(size_t optionIndex) const
|
||||
inline const QUrl &Download::downloadUrl(std::size_t optionIndex) const
|
||||
{
|
||||
return m_optionData.at(optionIndex).m_url;
|
||||
}
|
||||
|
@ -348,7 +348,7 @@ inline const QString &Download::collectionName() const
|
|||
* \remarks This information is possibly not available before the download is initiated.
|
||||
* \sa availableOption()
|
||||
*/
|
||||
inline size_t Download::availableOptionCount() const
|
||||
inline std::size_t Download::availableOptionCount() const
|
||||
{
|
||||
return m_optionData.size();
|
||||
}
|
||||
|
@ -372,7 +372,7 @@ inline bool Download::areOptionsAvailable() const
|
|||
* \remarks This information is possibly not available before the download is initiated.
|
||||
* \sa availableOptionCount()
|
||||
*/
|
||||
inline const QString &Download::optionName(size_t optionIndex) const
|
||||
inline const QString &Download::optionName(std::size_t optionIndex) const
|
||||
{
|
||||
if (optionIndex < m_optionData.size()) {
|
||||
return m_optionData.at(optionIndex).m_name;
|
||||
|
@ -405,7 +405,7 @@ inline bool Download::isValidOptionChosen() const
|
|||
*
|
||||
* The index might be invalid. Check isValidOptionChosen() before.
|
||||
*/
|
||||
inline size_t Download::chosenOption() const
|
||||
inline std::size_t Download::chosenOption() const
|
||||
{
|
||||
return m_chosenOption;
|
||||
}
|
||||
|
@ -538,7 +538,7 @@ inline int Download::positionInCollection() const
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the status update interval in miliseconds.
|
||||
* \brief Returns the status update interval in milliseconds.
|
||||
*/
|
||||
inline int Download::progressUpdateInterval() const
|
||||
{
|
||||
|
@ -547,7 +547,7 @@ inline int Download::progressUpdateInterval() const
|
|||
|
||||
/*!
|
||||
* \brief Sets the status interval.
|
||||
* \param value Specifies the status inverval in miliseconds.
|
||||
* \param value Specifies the status interval in milliseconds.
|
||||
*/
|
||||
inline void Download::setProgressUpdateInterval(int value)
|
||||
{
|
||||
|
@ -674,7 +674,7 @@ inline void Download::setTitle(const QString &value)
|
|||
* does nothing if a title has been set previously using the setTitle() method.
|
||||
* This might be useful since title information which is only derived from a
|
||||
* filename should generally not overwrite a title which has been obtained previously
|
||||
* from a better souce (for example the video meta data returned by YouTube in
|
||||
* from a better source (for example the video meta data returned by YouTube in
|
||||
* case of a YouTube download).
|
||||
*
|
||||
* \sa setTitle()
|
||||
|
@ -763,7 +763,7 @@ inline void Download::setCollectionName(const QString &value)
|
|||
* \brief Returns an indication whether the download is initiated.
|
||||
*
|
||||
* \remarks A download which has been failed might be initiated or not - depending
|
||||
* whether the failure occured during initialization or during the acutal download.
|
||||
* whether the failure occurred during initialization or during the actual download.
|
||||
*/
|
||||
inline bool Download::isInitiated() const
|
||||
{
|
||||
|
@ -878,7 +878,7 @@ inline CppUtilities::TimeSpan Download::shiftRemainingTime()
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of bytes received since the downlod has been started.
|
||||
* \brief Returns the number of bytes received since the download has been started.
|
||||
*/
|
||||
inline qint64 Download::bytesReceived() const
|
||||
{
|
||||
|
@ -917,7 +917,7 @@ inline qint64 Download::newBytesToReceive()
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns the number of miliseconds since the last progress update.
|
||||
* \brief Returns the number of milliseconds since the last progress update.
|
||||
*/
|
||||
inline int Download::lastProgressUpdate() const
|
||||
{
|
||||
|
@ -958,9 +958,9 @@ inline void Download::setStatusInfo(const QString &value)
|
|||
}
|
||||
|
||||
/*!
|
||||
* \brief Returns what kind of network error occured.
|
||||
* \brief Returns what kind of network error occurred.
|
||||
*
|
||||
* If no network error occured QNetworkReply::NoError is returned.
|
||||
* If no network error occurred QNetworkReply::NoError is returned.
|
||||
*/
|
||||
inline QNetworkReply::NetworkError Download::networkError() const
|
||||
{
|
||||
|
|
|
@ -50,7 +50,7 @@ void FileNukeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer
|
|||
query.addQueryItem(QStringLiteral("fname"), fname);
|
||||
query.addQueryItem(QStringLiteral("referer"), QString());
|
||||
query.addQueryItem(QStringLiteral("method_free"), QStringLiteral("Free"));
|
||||
m_postData.append(query.toString(QUrl::FullyEncoded));
|
||||
m_postData.append(query.toString(QUrl::FullyEncoded).toUtf8());
|
||||
++m_currentStep;
|
||||
doInit();
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ void FileNukeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer
|
|||
pos = videoInfo.indexOf(QLatin1String(",'"), pos + 1);
|
||||
if (pos > 0) {
|
||||
substring(videoInfo, str, pos, QStringLiteral("'"), QStringLiteral("'"));
|
||||
QStringList parts = str.split(QChar('|'), QString::KeepEmptyParts);
|
||||
QStringList parts = str.split(QChar('|'), Qt::KeepEmptyParts);
|
||||
|
||||
if (parts.count() >= 21) {
|
||||
addDownloadUrl(tr("H.264/AAC/MP4"),
|
||||
|
|
|
@ -29,12 +29,12 @@ public:
|
|||
Download *downloadByInitialUrl(const QUrl &url) const;
|
||||
bool hasDownloadUrl(const QUrl &url) const;
|
||||
|
||||
public slots:
|
||||
public Q_SLOTS:
|
||||
bool start();
|
||||
void stop();
|
||||
void setContinueAutomatically(bool continueAutomatically);
|
||||
|
||||
signals:
|
||||
Q_SIGNALS:
|
||||
void requestCreated(Download *request);
|
||||
void aboutToMakeNewResultsAvailable(unsigned int count);
|
||||
void newResultsAvailable(const QList<Download *> &newResults);
|
||||
|
@ -47,7 +47,7 @@ protected:
|
|||
* \brief Specifies possible return values of the evalResults() method.
|
||||
*/
|
||||
enum class ParsingResult {
|
||||
Error, /**< Indicates that an error occured. reasonForFail might hold an error message. */
|
||||
Error, /**< Indicates that an error occurred. reasonForFail might hold an error message. */
|
||||
Success, /**< Indicates that the results could be parsed correctly. */
|
||||
AnotherRequestRequired /**< Indicates that the results could be parsed correctly but there are still results to be fetched. */
|
||||
};
|
||||
|
@ -59,7 +59,7 @@ protected:
|
|||
void reportCollectionTitle(const QString &title);
|
||||
void reportResult(Download *result);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void downloadChangedStatus(Download *download);
|
||||
void downloadRequiresOutputDevice(Download *download, size_t option);
|
||||
|
||||
|
|
|
@ -132,7 +132,7 @@ DownloadFinder::ParsingResult GroovesharkSearcher::parseResults(const QByteArray
|
|||
QJsonObject itemObj;
|
||||
QJsonValue idVal;
|
||||
QJsonValue verifiedVal;
|
||||
foreach (QJsonValue itemVal, collectionArray) {
|
||||
for (const QJsonValue &itemVal : collectionArray) {
|
||||
if (itemVal.isObject()) {
|
||||
itemObj = itemVal.toObject();
|
||||
if (m_verified) { // skip unverified items if verified option used
|
||||
|
@ -184,7 +184,7 @@ DownloadFinder::ParsingResult GroovesharkSearcher::parseResults(const QByteArray
|
|||
QJsonValue titleVal;
|
||||
QJsonValue durationVal;
|
||||
QJsonValue trackNumVal;
|
||||
foreach (QJsonValue songVal, songsArray) {
|
||||
for (const QJsonValue songVal : songsArray) {
|
||||
if (songVal.isObject()) {
|
||||
songObj = songVal.toObject();
|
||||
idVal = songObj.value(QStringLiteral("SongID"));
|
||||
|
|
|
@ -30,7 +30,7 @@ public:
|
|||
protected:
|
||||
Download *createRequest(QString &reasonForFail);
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
ParsingResult parseResults(const QByteArray &data, QString &reasonForFail);
|
||||
|
||||
private:
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
#include "../../application/utils.h"
|
||||
|
||||
#include <QRegExp>
|
||||
#include <QRegularExpression>
|
||||
|
||||
using namespace CppUtilities;
|
||||
using namespace Application;
|
||||
|
@ -33,64 +33,61 @@ Download *LinkFinder::createRequest(QString &)
|
|||
DownloadFinder::ParsingResult LinkFinder::parseResults(const QByteArray &data, QString &)
|
||||
{
|
||||
QString html(data);
|
||||
QRegExp titlePattern(QStringLiteral("<title>(.+)</title>"), Qt::CaseInsensitive);
|
||||
QRegExp linkPattern(QStringLiteral("<a([^>]+)>(.+)</a>"), Qt::CaseInsensitive);
|
||||
QRegExp commentPattern(QStringLiteral("<!--(.+)-->"), Qt::CaseInsensitive);
|
||||
QRegExp hrefPattern1(QStringLiteral("\\s*href\\s*=\\s*['](.+)['>]"), Qt::CaseInsensitive);
|
||||
QRegExp hrefPattern2(QStringLiteral("\\s*href\\s*=\\s*[\"](.+)[\">]"), Qt::CaseInsensitive);
|
||||
titlePattern.setMinimal(true);
|
||||
linkPattern.setMinimal(true);
|
||||
commentPattern.setMinimal(true);
|
||||
hrefPattern1.setMinimal(true);
|
||||
hrefPattern2.setMinimal(true);
|
||||
static const QRegularExpression titlePattern(
|
||||
QStringLiteral("<title>(.+)</title>"), QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption);
|
||||
static const QRegularExpression linkPattern(
|
||||
QStringLiteral("<a([^>]+)>(.+)</a>"), QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption);
|
||||
static const QRegularExpression commentPattern(
|
||||
QStringLiteral("<!--(.+)-->"), QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption);
|
||||
static const QRegularExpression hrefPattern1(
|
||||
QStringLiteral("\\s*href\\s*=\\s*['](.+)['>]"), QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption);
|
||||
static const QRegularExpression hrefPattern2(
|
||||
QStringLiteral("\\s*href\\s*=\\s*[\"](.+)[\">]"), QRegularExpression::CaseInsensitiveOption | QRegularExpression::InvertedGreedinessOption);
|
||||
QString pageTitle;
|
||||
if (titlePattern.indexIn(html) >= 0 && titlePattern.captureCount() >= 1) {
|
||||
pageTitle = titlePattern.cap(1);
|
||||
const auto titleMatch = titlePattern.match(html);
|
||||
if (titleMatch.hasMatch()) {
|
||||
pageTitle = titleMatch.captured(1);
|
||||
replaceHtmlEntities(pageTitle);
|
||||
}
|
||||
int overallIndex = 0;
|
||||
int commentIndex = commentPattern.indexIn(html, overallIndex);
|
||||
int linkIndex = 0;
|
||||
while (((linkIndex = linkPattern.indexIn(html, overallIndex)) >= 0)) {
|
||||
if (commentIndex >= 0 && commentIndex < linkIndex) {
|
||||
auto commentMatch = commentPattern.match(html, 0);
|
||||
decltype(commentMatch.capturedEnd()) overallIndex = 0;
|
||||
for (auto linkMatch = linkPattern.match(html, overallIndex); linkMatch.hasMatch(); linkMatch = linkPattern.match(html, overallIndex)) {
|
||||
if (commentMatch.capturedStart() >= 0 && commentMatch.capturedStart() < linkMatch.capturedStart()) {
|
||||
// skip comment
|
||||
overallIndex = commentIndex + commentPattern.matchedLength();
|
||||
commentIndex = commentPattern.indexIn(html, overallIndex);
|
||||
} else if (linkIndex >= 0) {
|
||||
// read actual link
|
||||
if (linkPattern.captureCount() >= 2) {
|
||||
QString title(linkPattern.cap(2));
|
||||
QString href(linkPattern.cap(1));
|
||||
QString urlStr;
|
||||
if (hrefPattern1.indexIn(href) >= 0 && hrefPattern1.captureCount() >= 1) {
|
||||
urlStr = hrefPattern1.cap(1);
|
||||
} else if (hrefPattern2.indexIn(href) >= 0 && hrefPattern2.captureCount() >= 1) {
|
||||
urlStr = hrefPattern2.cap(1);
|
||||
}
|
||||
if (!urlStr.isEmpty()) {
|
||||
replaceHtmlEntities(title);
|
||||
replaceHtmlEntities(urlStr);
|
||||
// resolve relative URLs
|
||||
QUrl url(urlStr);
|
||||
if (url.isRelative()) {
|
||||
url = m_url.resolved(url);
|
||||
}
|
||||
// avoid duplicate results
|
||||
if (Download *duplicateDownload = downloadByInitialUrl(url)) {
|
||||
if (!title.isEmpty() && duplicateDownload->title().isEmpty()) {
|
||||
duplicateDownload->provideMetaData(title);
|
||||
}
|
||||
} else if (Download *result = Download::fromUrl(url)) {
|
||||
result->provideMetaData(title, QString(), TimeSpan(), pageTitle, results().size());
|
||||
reportResult(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
overallIndex = linkIndex + linkPattern.matchedLength();
|
||||
} else {
|
||||
// no more links
|
||||
overallIndex = commentMatch.capturedEnd();
|
||||
commentMatch = commentPattern.match(html, overallIndex);
|
||||
break;
|
||||
}
|
||||
// read actual link
|
||||
QString title = linkMatch.captured(2), href = linkMatch.captured(1), urlStr;
|
||||
const auto hrefMatch1 = hrefPattern1.match(href);
|
||||
if (hrefMatch1.hasMatch()) {
|
||||
urlStr = hrefMatch1.captured(1);
|
||||
} else {
|
||||
const auto hrefMatch2 = hrefPattern2.match(href);
|
||||
if (hrefMatch2.hasMatch()) {
|
||||
urlStr = hrefMatch2.captured(1);
|
||||
}
|
||||
}
|
||||
if (!urlStr.isEmpty()) {
|
||||
replaceHtmlEntities(title);
|
||||
replaceHtmlEntities(urlStr);
|
||||
// resolve relative URLs
|
||||
QUrl url(urlStr);
|
||||
if (url.isRelative()) {
|
||||
url = m_url.resolved(url);
|
||||
}
|
||||
// avoid duplicate results
|
||||
if (Download *const duplicateDownload = downloadByInitialUrl(url)) {
|
||||
if (!title.isEmpty() && duplicateDownload->title().isEmpty()) {
|
||||
duplicateDownload->provideMetaData(title);
|
||||
}
|
||||
} else if (Download *result = Download::fromUrl(url)) {
|
||||
result->provideMetaData(title, QString(), TimeSpan(), pageTitle, results().size());
|
||||
reportResult(result);
|
||||
}
|
||||
}
|
||||
overallIndex = linkMatch.capturedEnd();
|
||||
}
|
||||
return DownloadFinder::ParsingResult::Success;
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ public:
|
|||
protected:
|
||||
Download *createRequest(QString &);
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
ParsingResult parseResults(const QByteArray &data, QString &);
|
||||
|
||||
private:
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
protected:
|
||||
Download *createRequest(QString &reasonForFail);
|
||||
|
||||
protected slots:
|
||||
protected Q_SLOTS:
|
||||
ParsingResult parseResults(const QByteArray &data, QString &reasonForFail);
|
||||
|
||||
private:
|
||||
|
|
|
@ -304,7 +304,7 @@ bool GroovesharkDownload::loadAuthenticationInformationFromFile(const QString &p
|
|||
}
|
||||
clientVal = fileObj.value(QStringLiteral("referer"));
|
||||
if (clientVal.isString()) {
|
||||
m_referer.append(clientVal.toString());
|
||||
m_referer.append(clientVal.toString().toUtf8());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -316,18 +316,18 @@ bool GroovesharkDownload::loadAuthenticationInformationFromFile(const QString &p
|
|||
QJsonValue GroovesharkDownload::generateTokenHash(QString method, int mode)
|
||||
{
|
||||
QByteArray toHash;
|
||||
toHash.append(method);
|
||||
toHash.append(method.toUtf8());
|
||||
toHash.append(':');
|
||||
toHash.append(m_token);
|
||||
toHash.append(m_token.toUtf8());
|
||||
switch (mode) {
|
||||
case 1:
|
||||
toHash.append(m_htmlRandomizer);
|
||||
toHash.append(m_htmlRandomizer.toUtf8());
|
||||
break;
|
||||
default:
|
||||
toHash.append(m_jsRandomizer);
|
||||
toHash.append(m_jsRandomizer.toUtf8());
|
||||
break;
|
||||
}
|
||||
toHash.append(m_anyRandomizer);
|
||||
toHash.append(m_anyRandomizer.toUtf8());
|
||||
QString res;
|
||||
res.append(m_anyRandomizer);
|
||||
res.append(QString(QCryptographicHash::hash(toHash, QCryptographicHash::Sha1).toHex()).toLower());
|
||||
|
@ -340,7 +340,7 @@ QJsonValue GroovesharkDownload::generateTokenHash(QString method, int mode)
|
|||
QJsonValue GroovesharkDownload::generateSecretKey()
|
||||
{
|
||||
QByteArray toHash;
|
||||
toHash.append(m_sessionId.toString());
|
||||
toHash.append(m_sessionId.toString().toUtf8());
|
||||
QString secretKey(QCryptographicHash::hash(toHash, QCryptographicHash::Md5).toHex());
|
||||
return QJsonValue(secretKey);
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ HttpDownload *GroovesharkDownload::createJsonPostRequest(const QString &method,
|
|||
HttpDownload *download = new HttpDownload(QUrl(url));
|
||||
download->setMethod(HttpDownloadMethod::Post);
|
||||
download->setPostData(postData);
|
||||
download->setHeader(QNetworkRequest::ContentTypeHeader, QStringLiteral("application/json"));
|
||||
download->setHeader(QNetworkRequest::ContentTypeHeader, QVariant(QLatin1String("application/json")));
|
||||
download->setHeader("Refer", m_referer);
|
||||
download->setHeader("Accept", m_accept);
|
||||
//download->setHeader("Connection", "keep-alive");
|
||||
|
@ -379,12 +379,12 @@ void GroovesharkDownload::setupFinalRequest()
|
|||
setMethod(HttpDownloadMethod::Post);
|
||||
switch (m_requestType) {
|
||||
case GroovesharkRequestType::SongStream: {
|
||||
setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||
setHeader(QNetworkRequest::ContentTypeHeader, QVariant(QLatin1String("application/x-www-form-urlencoded")));
|
||||
setHeader("Accept", m_accept);
|
||||
QUrlQuery query;
|
||||
query.addQueryItem("streamKey", m_streamKey);
|
||||
QByteArray postData;
|
||||
postData.append(query.toString(QUrl::FullyEncoded));
|
||||
postData.append(query.toString(QUrl::FullyEncoded).toUtf8());
|
||||
setPostData(postData);
|
||||
addDownloadUrl(tr("MPEG-1 Layer 3"), QUrl(QStringLiteral("http://%1/stream.php").arg(m_streamHost)));
|
||||
break;
|
||||
|
|
|
@ -78,13 +78,13 @@ void HttpDownload::startRequest(size_t optionIndex)
|
|||
QByteArray rangeVal;
|
||||
rangeVal.append("bytes=");
|
||||
if (currentOffset > 0) {
|
||||
rangeVal.append(QString::number(currentOffset));
|
||||
rangeVal.append(QString::number(currentOffset).toUtf8());
|
||||
} else {
|
||||
rangeVal.append('0');
|
||||
}
|
||||
rangeVal.append('-');
|
||||
if (endOffset > 0) {
|
||||
rangeVal.append(QString::number(endOffset));
|
||||
rangeVal.append(QString::number(endOffset).toUtf8());
|
||||
}
|
||||
m_request.setRawHeader("Range", rangeVal);
|
||||
} else {
|
||||
|
@ -145,13 +145,13 @@ void HttpDownload::checkStatusAndClear(size_t optionIndex)
|
|||
// wrong to report a failed download here?
|
||||
reportFinalDownloadStatus(optionIndex, false, reasonForFail, error);
|
||||
} else {
|
||||
// some other error occured
|
||||
// some other error occurred
|
||||
reply->deleteLater();
|
||||
m_replies.removeAll(reply);
|
||||
reportFinalDownloadStatus(optionIndex, false, reasonForFail, error);
|
||||
}
|
||||
} else {
|
||||
// no error occured
|
||||
// no error occurred
|
||||
// check if there's a redirection
|
||||
QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
|
||||
reply->deleteLater();
|
||||
|
|
|
@ -100,7 +100,7 @@ public:
|
|||
QString typeName() const;
|
||||
//bool isPending(QNetworkReply *reply) const;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void slotFinished();
|
||||
void slotReadyRead();
|
||||
void slotDownloadProgress(qint64 bytesReceived, qint64 bytesToReceive);
|
||||
|
|
|
@ -65,7 +65,7 @@ void HttpDownloadWithInfoRequst::infoRequestChangedStatus(Download *download)
|
|||
{
|
||||
switch (download->status()) {
|
||||
case DownloadStatus::Failed:
|
||||
reportInitiated(false, tr("Couldn't retieve the video information. %1").arg(statusInfo()));
|
||||
reportInitiated(false, tr("Couldn't retrieve the video information. %1").arg(statusInfo()));
|
||||
break;
|
||||
case DownloadStatus::Ready:
|
||||
if (m_infoDownload->isValidOptionChosen()) {
|
||||
|
|
|
@ -25,7 +25,7 @@ public:
|
|||
protected:
|
||||
virtual void evalVideoInformation(Download *, QBuffer *) = 0;
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void infoRequestChangedStatus(Download *download);
|
||||
|
||||
private:
|
||||
|
|
|
@ -51,7 +51,7 @@ void ContentDispositionParser::pharse()
|
|||
PharsingPosition pos = FieldName;
|
||||
QString fieldName;
|
||||
QString value;
|
||||
foreach (QChar c, m_contentDisposition) {
|
||||
for (QChar c : m_contentDisposition) {
|
||||
if (c == '\"') {
|
||||
inQuotationMarks = !inQuotationMarks;
|
||||
} else if (c == ';') {
|
||||
|
|
|
@ -72,7 +72,7 @@ void SockshareDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffe
|
|||
QUrlQuery query;
|
||||
query.addQueryItem(QStringLiteral("hash"), str);
|
||||
query.addQueryItem(QStringLiteral("confirm"), QStringLiteral("Continue as Free User"));
|
||||
m_postData.append(query.toString(QUrl::FullyEncoded));
|
||||
m_postData.append(query.toString(QUrl::FullyEncoded).toUtf8());
|
||||
m_currentStep++;
|
||||
doInit();
|
||||
}
|
||||
|
|
|
@ -1,153 +0,0 @@
|
|||
#include "./spotifydownload.h"
|
||||
|
||||
#include "../application/utils.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QJsonArray>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
#include <QUrlQuery>
|
||||
|
||||
using namespace Application;
|
||||
|
||||
namespace Network {
|
||||
|
||||
const QUrl SpotifyDownload::m_spotifyUrl = QUrl(QStringLiteral("https://play.spotify.com/"));
|
||||
bool SpotifyDownload::m_authenticationCredentialsValidated = false;
|
||||
QString SpotifyDownload::m_csrftoken = QString();
|
||||
QString SpotifyDownload::m_trackingId = QString();
|
||||
QString SpotifyDownload::m_referrer = QString();
|
||||
QString SpotifyDownload::m_creationFlow = QString();
|
||||
QStringList SpotifyDownload::m_supportedUseragents = QStringList()
|
||||
<< QStringLiteral("Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:23.0) Gecko/20100101 Firefox/23.0");
|
||||
|
||||
/*!
|
||||
* \class SpotifyDownload
|
||||
* \brief Download implementation for Spotify songs.
|
||||
* \remarks Under construction (not even rudimental finished).
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a new SpotifyDownload for the specified \a songid.
|
||||
*/
|
||||
SpotifyDownload::SpotifyDownload(const QString &songid, QObject *parent)
|
||||
: HttpDownloadWithInfoRequst(QUrl(), parent)
|
||||
, m_currentRequest(SpotifyRequestType::Invalid)
|
||||
, m_triesToGetAuthenticationData(0)
|
||||
{
|
||||
setId(songid);
|
||||
}
|
||||
|
||||
QString SpotifyDownload::typeName() const
|
||||
{
|
||||
return tr("Spotify");
|
||||
}
|
||||
|
||||
void SpotifyDownload::resetSession()
|
||||
{
|
||||
m_authenticationCredentialsValidated = false;
|
||||
m_csrftoken.clear();
|
||||
m_trackingId.clear();
|
||||
m_referrer.clear();
|
||||
m_creationFlow.clear();
|
||||
}
|
||||
|
||||
Download *SpotifyDownload::infoRequestDownload(bool &success, QString &reasonForFail)
|
||||
{
|
||||
HttpDownload *download = nullptr;
|
||||
if (m_csrftoken.isEmpty() || m_trackingId.isEmpty() /* || creationFlow.isEmpty()*/) {
|
||||
if (m_triesToGetAuthenticationData < 2) {
|
||||
download = new HttpDownload(m_spotifyUrl);
|
||||
download->setCustomUserAgent(m_supportedUseragents.at(0));
|
||||
success = true;
|
||||
++m_triesToGetAuthenticationData;
|
||||
m_currentRequest = SpotifyRequestType::GetAuthenticationData;
|
||||
} else {
|
||||
reasonForFail = tr("Unable to find data required for autentication.");
|
||||
success = false;
|
||||
}
|
||||
} else if (!m_authenticationCredentialsValidated) {
|
||||
if (initialAuthenticationCredentials().isIncomplete()) {
|
||||
reportAuthenticationRequired(
|
||||
-1, tr("To download songs from Spotify authentication is required so you have to enter the credentials of your Spotify account."));
|
||||
reasonForFail = tr("Authentication credentials not given.");
|
||||
//networkError = QNetworkReply::AuthenticationRequiredError;
|
||||
success = false;
|
||||
} else {
|
||||
QUrl url(m_spotifyUrl);
|
||||
url.setPath(QStringLiteral("/xhr/json/auth.php"));
|
||||
download = new HttpDownload(url);
|
||||
QByteArray postData;
|
||||
QUrlQuery query;
|
||||
query.addQueryItem(QStringLiteral("type"), QStringLiteral("sp"));
|
||||
query.addQueryItem(QStringLiteral("username"), initialAuthenticationCredentials().userName());
|
||||
query.addQueryItem(QStringLiteral("password"), initialAuthenticationCredentials().password());
|
||||
query.addQueryItem(QStringLiteral("secret"), m_csrftoken);
|
||||
query.addQueryItem(QStringLiteral("trackingId"), m_trackingId);
|
||||
query.addQueryItem(QStringLiteral("landingURL"), m_spotifyUrl.toString());
|
||||
query.addQueryItem(QStringLiteral("cf"), m_creationFlow);
|
||||
postData.append(query.toString(QUrl::FullyEncoded));
|
||||
download->setMethod(HttpDownloadMethod::Post);
|
||||
download->setPostData(postData);
|
||||
download->setCustomUserAgent(m_supportedUseragents.at(0));
|
||||
|
||||
success = true;
|
||||
m_currentRequest = SpotifyRequestType::Authenticate;
|
||||
}
|
||||
}
|
||||
return download;
|
||||
}
|
||||
|
||||
void SpotifyDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
||||
{
|
||||
if (m_currentRequest == SpotifyRequestType::Invalid)
|
||||
reportInitiated(false, tr("Interal error (current request type not set)."));
|
||||
else {
|
||||
switch (m_currentRequest) {
|
||||
case SpotifyRequestType::GetAuthenticationData: {
|
||||
QString responseData(videoInfoBuffer->readAll());
|
||||
substring(responseData, m_csrftoken, 0, QStringLiteral("\"csrftoken\":\""), QStringLiteral("\""));
|
||||
substring(responseData, m_trackingId, 0, QStringLiteral("\"trackingId\":\""), QStringLiteral("\""));
|
||||
substring(responseData, m_creationFlow, 0, QStringLiteral("\"creationFlow\":\""), QStringLiteral("\""));
|
||||
substring(responseData, m_referrer, 0, QStringLiteral("\"referrer\":\""), QStringLiteral("\""));
|
||||
m_currentRequest = SpotifyRequestType::Invalid;
|
||||
doInit();
|
||||
break;
|
||||
}
|
||||
case SpotifyRequestType::Authenticate: {
|
||||
QByteArray responseData(videoInfoBuffer->readAll());
|
||||
QApplication::clipboard()->setText(QString(responseData));
|
||||
QJsonParseError error;
|
||||
QJsonDocument document = QJsonDocument::fromJson(responseData, &error);
|
||||
if (error.error == QJsonParseError::NoError) {
|
||||
QJsonObject obj = document.object();
|
||||
QJsonValue statusVal = obj.value(QStringLiteral("status"));
|
||||
if (statusVal.toString().compare(QLatin1String("ok"), Qt::CaseInsensitive) == 0) {
|
||||
m_authenticationCredentialsValidated = true;
|
||||
reportInitiated(true);
|
||||
} else {
|
||||
QString error = obj.value(QStringLiteral("error")).toString();
|
||||
QString message;
|
||||
if (error.isEmpty()) {
|
||||
message = tr("Authentication failed. Spotify returned no error message.");
|
||||
} else if (error.compare(QLatin1String("invalid_credentials"), Qt::CaseInsensitive) == 0) {
|
||||
message = tr("Authentication failed because the entered credentials are invalid.");
|
||||
} else {
|
||||
message = tr("Authentication failed. Error message returned by Spotify: %1").arg(error);
|
||||
}
|
||||
reportInitiated(false, message);
|
||||
}
|
||||
} else {
|
||||
reportInitiated(false,
|
||||
tr("Authentication failed because the response by Spotify is no valid Json document (parse error: %1).")
|
||||
.arg(error.errorString()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SpotifyRequestType::Invalid:;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace Network
|
|
@ -1,40 +0,0 @@
|
|||
#ifndef SPOTIFYDOWNLOAD_H
|
||||
#define SPOTIFYDOWNLOAD_H
|
||||
|
||||
#include "./httpdownloadwithinforequst.h"
|
||||
|
||||
namespace Network {
|
||||
|
||||
enum class SpotifyRequestType { Invalid, GetAuthenticationData, Authenticate };
|
||||
|
||||
class SpotifyDownload : public HttpDownloadWithInfoRequst {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit SpotifyDownload(const QString &songid, QObject *parent = nullptr);
|
||||
|
||||
Download *infoRequestDownload(bool &success, QString &reasonForFail);
|
||||
QString typeName() const;
|
||||
|
||||
static void resetSession();
|
||||
|
||||
protected:
|
||||
void evalVideoInformation(Download *, QBuffer *videoInfoBuffer);
|
||||
|
||||
private:
|
||||
// static fields
|
||||
static const QUrl m_spotifyUrl;
|
||||
static bool m_authenticationCredentialsValidated;
|
||||
static QString m_csrftoken;
|
||||
static QString m_trackingId;
|
||||
static QString m_referrer;
|
||||
static QString m_creationFlow;
|
||||
static QStringList m_supportedUseragents;
|
||||
|
||||
// fields
|
||||
SpotifyRequestType m_currentRequest;
|
||||
int m_triesToGetAuthenticationData;
|
||||
};
|
||||
} // namespace Network
|
||||
|
||||
#endif // SPOTIFYDOWNLOAD_H
|
|
@ -21,7 +21,7 @@ protected:
|
|||
void doInit();
|
||||
void checkStatusAndClear(size_t);
|
||||
|
||||
private slots:
|
||||
private Q_SLOTS:
|
||||
void tick();
|
||||
|
||||
private:
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
#include "./vimeodownload.h"
|
||||
|
||||
#include <qtutilities/misc/compat.h>
|
||||
|
||||
#include <c++utilities/chrono/timespan.h>
|
||||
|
||||
#include <QJsonDocument>
|
||||
|
@ -33,19 +35,11 @@ VimeoDownload::VimeoDownload(const QString &id, QObject *parent)
|
|||
|
||||
Download *VimeoDownload::infoRequestDownload(bool &success, QString &reasonForFail)
|
||||
{
|
||||
const auto pathParts = initialUrl()
|
||||
.path(QUrl::FullyDecoded)
|
||||
.
|
||||
#if QT_VERSION >= 0x050400
|
||||
splitRef
|
||||
#else
|
||||
split
|
||||
#endif
|
||||
(QChar('/'), QString::SkipEmptyParts);
|
||||
const auto pathParts = QtUtilities::splitRef(initialUrl().path(QUrl::FullyDecoded), QChar('/'), Qt::SkipEmptyParts);
|
||||
if (pathParts.size() < 2) {
|
||||
const auto &id = pathParts.back();
|
||||
bool isInt;
|
||||
id.toULongLong(&isInt);
|
||||
static_cast<void>(id.toULongLong(&isInt));
|
||||
if (isInt) {
|
||||
setId(id
|
||||
#if QT_VERSION >= 0x050400
|
||||
|
|
|
@ -62,9 +62,9 @@ void YoutubeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
|||
m_itagInfo = loadJsonObjectFromResource(QStringLiteral(":/jsonobjects/itaginfo"));
|
||||
}
|
||||
QString videoInfo(videoInfoBuffer->readAll());
|
||||
QStringList completeFields = videoInfo.split(QChar('&'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||
foreach (QString completeField, completeFields) {
|
||||
QStringList fieldParts = completeField.split(QChar('='), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||
QStringList completeFields = videoInfo.split(QChar('&'), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
for (const QString &completeField : completeFields) {
|
||||
QStringList fieldParts = completeField.split(QChar('='), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
if (fieldParts.count() < 2) {
|
||||
continue;
|
||||
}
|
||||
|
@ -90,16 +90,16 @@ void YoutubeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
|||
setRating(rating);
|
||||
}
|
||||
QStringList fmtFieldIds = QStringList() << QStringLiteral("url_encoded_fmt_stream_map") << QStringLiteral("adaptive_fmts");
|
||||
foreach (const QString &fmtFieldId, fmtFieldIds) {
|
||||
for (const QString &fmtFieldId : fmtFieldIds) {
|
||||
QString fmtField = m_fields.value(fmtFieldId, QString());
|
||||
if (!fmtField.isEmpty()) {
|
||||
QStringList sections = fmtField.split(QChar(','), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||
foreach (QString section, sections) {
|
||||
QStringList fmtParts = section.split(QChar('&'), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||
QStringList sections = fmtField.split(QChar(','), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
for (const QString §ion : sections) {
|
||||
QStringList fmtParts = section.split(QChar('&'), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
QString itag, urlPart1, urlPart2, name;
|
||||
QJsonObject itagObj;
|
||||
foreach (QString fmtPart, fmtParts) {
|
||||
QStringList fmtSubParts = fmtPart.split(QChar('='), QString::SkipEmptyParts, Qt::CaseSensitive);
|
||||
for (const QString fmtPart : fmtParts) {
|
||||
QStringList fmtSubParts = fmtPart.split(QChar('='), Qt::SkipEmptyParts, Qt::CaseSensitive);
|
||||
if (fmtSubParts.count() >= 2) {
|
||||
QString fieldIdentifier = fmtSubParts.at(0).toLower();
|
||||
if (fieldIdentifier == QLatin1String("url")) {
|
||||
|
@ -146,10 +146,10 @@ void YoutubeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
|||
name = itag;
|
||||
}
|
||||
QByteArray url;
|
||||
url.append(urlPart1);
|
||||
url.append(urlPart1.toUtf8());
|
||||
if (!urlPart2.isEmpty()) {
|
||||
url.append("&signature=");
|
||||
url.append(urlPart2);
|
||||
url.append(urlPart2.toUtf8());
|
||||
}
|
||||
addDownloadUrl(name, QUrl::fromPercentEncoding(url));
|
||||
m_itags.append(itag);
|
||||
|
@ -167,10 +167,10 @@ void YoutubeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
|
|||
QString reason = m_fields.value("reason");
|
||||
if (reason.isEmpty()) {
|
||||
reportInitiated(false,
|
||||
tr("Failed to retieve the video info. The reason couldn't be identified. It seems like YouTube changed something in their API."));
|
||||
tr("Failed to retrieve the video info. The reason couldn't be identified. It seems like YouTube changed something in their API."));
|
||||
} else {
|
||||
reportInitiated(false,
|
||||
tr("Failed to retieve the video info. The reason returned by Youtube is: \"%1\".").arg(reason.replace(QChar('+'), QChar(' '))));
|
||||
tr("Failed to retrieve the video info. The reason returned by Youtube is: \"%1\".").arg(reason.replace(QChar('+'), QChar(' '))));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ QString YoutubeDownload::suitableFilename() const
|
|||
originalOption = options().at(originalOption).redirectionOf();
|
||||
}
|
||||
QString extension;
|
||||
if (originalOption < static_cast<size_t>(m_itags.size())) {
|
||||
if (originalOption < static_cast<std::size_t>(m_itags.size())) {
|
||||
const auto itag = m_itags.at(originalOption);
|
||||
if (m_itagInfo.contains(itag)) {
|
||||
const auto itagObj = m_itagInfo.value(itag).toObject();
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/hicolor/128x128/apps/videodownloader.png</file>
|
||||
<file>icons/hicolor/32x32/categories/preferences-general.png</file>
|
||||
<file>icons/hicolor/32x32/categories/preferences-network.png</file>
|
||||
<file>icons/hicolor/32x32/categories/preferences-specific.png</file>
|
||||
<file>icons/hicolor/32x32/categories/applications-internet.svg</file>
|
||||
<file>icons/hicolor/32x32/categories/preferences-other.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 4.4 KiB |
Before Width: | Height: | Size: 66 KiB |
Before Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 3.3 KiB |
|
@ -0,0 +1 @@
|
|||
<svg height="32" width="32" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><linearGradient id="b" gradientUnits="userSpaceOnUse" x1="2" x2="2" y1="30" y2="2"><stop offset="0" stop-color="#197cf1"/><stop offset="1" stop-color="#20bcfa"/></linearGradient><linearGradient id="d" gradientUnits="userSpaceOnUse" x1="23" x2="30" xlink:href="#a" y1="13" y2="20"/><linearGradient id="a"><stop offset="0" stop-color="#292c2f"/><stop offset="1" stop-opacity="0"/></linearGradient><linearGradient id="c" gradientUnits="userSpaceOnUse" x1="6" x2="26" xlink:href="#a" y1="6" y2="26"/><linearGradient id="e" gradientUnits="userSpaceOnUse" x1="2" x2="2" y1="30" y2="2"><stop offset="0" stop-color="#54d883"/><stop offset="1" stop-color="#abf9c7"/></linearGradient><rect fill="url(#b)" height="28" rx="14" width="28" x="2" y="2"/><path d="M16 2A13.965 13.965 0 0 0 2.078 14.53l.543.07L6 17l7.188 4.133 1.47 8.799A13.97 13.97 0 0 0 30 16c0-7.756-6.244-14-14-14z" fill="url(#c)" fill-rule="evenodd" opacity=".2"/><path d="M29.73 13.27L25 18l3.758 3.758a13.984 13.984 0 0 0 .972-8.488z" fill="url(#d)" fill-rule="evenodd" opacity=".2"/><path d="M16 2a14 14 0 0 0-13.059 9H3l3-1 1 1 1 1v-2l2-1V8l2-1 2-2v1l1-1-1-1h2v1l2-1-1-1v-.95A14 14 0 0 0 16 2zm10.375 4.625L26 7v1h1.469a14 14 0 0 0-1.094-1.375zm1.316 1.684L27 9l-2 2-1 1-1 3v1l1 1 1 1 2 1 2.791-.688A14 14 0 0 0 30 16a14 14 0 0 0-2.309-7.691zM4 13l-1 1h-.838c-.05.34-.088.681-.113 1.023v.002L4 16l1 1 2 1 1 1-1 1v2l1 2 2 2v2.629A14 14 0 0 0 16 30c.17-.003.34-.009.51-.018L17 29v-1l2-1 1-1v-2l1-1v-1l-1-1-3-1-1-1-1-1h-1l-1-1-3-1-2 1H6v-2H5v-2z" fill="url(#e)"/><path d="M29.979 15.414A14 14 0 0 1 16 29 14 14 0 0 1 2.021 15.586 14 14 0 0 0 2 16a14 14 0 0 0 14 14 14 14 0 0 0 14-14 14 14 0 0 0-.021-.586z" fill="#292c2f" opacity=".2"/></svg>
|
After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 1.9 KiB |
Before Width: | Height: | Size: 2.6 KiB |
|
@ -0,0 +1,28 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
<svg width="32" version="1.1" xmlns="http://www.w3.org/2000/svg" height="32" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape">
|
||||
<defs id="defs5455">
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4303" id="linearGradient4238" y1="545.79797" y2="517.79797" x2="0" gradientUnits="userSpaceOnUse" gradientTransform="matrix(1 0 0 1 -0.000006 0)"/>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4159" id="linearGradient4370" y1="30" y2="1.999974" x2="0" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" id="linearGradient4303">
|
||||
<stop style="stop-color:#c6cdd1" id="stop4305"/>
|
||||
<stop offset="1" style="stop-color:#e0e5e7" id="stop4307"/>
|
||||
</linearGradient>
|
||||
<linearGradient inkscape:collect="always" id="linearGradient4159">
|
||||
<stop style="stop-color:#2a2c2f" id="stop4161"/>
|
||||
<stop offset="1" style="stop-color:#424649" id="stop4163"/>
|
||||
</linearGradient>
|
||||
<linearGradient inkscape:collect="always" xlink:href="#linearGradient4227" id="linearGradient4198" y1="9" x1="9.00001" y2="22.999973" x2="23" gradientUnits="userSpaceOnUse"/>
|
||||
<linearGradient inkscape:collect="always" id="linearGradient4227">
|
||||
<stop style="stop-color:#292c2f" id="stop4229"/>
|
||||
<stop offset="1" style="stop-opacity:0" id="stop4231"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<metadata id="metadata5458"/>
|
||||
<g inkscape:label="Capa 1" inkscape:groupmode="layer" id="layer1" transform="matrix(1 0 0 1 -384.57143 -515.798)">
|
||||
<rect width="27.999989" x="386.57144" y="517.79797" rx="13.999994" height="28" style="fill:url(#linearGradient4238)" id="rect4175"/>
|
||||
<path inkscape:connector-curvature="0" style="fill:url(#linearGradient4198);opacity:0.2;fill-rule:evenodd" id="path4175" d="m 9.4003906,15 -0.099609,2 0.9999998,1 10.970703,10.970703 c 3.4891,-1.412467 6.267011,-4.183045 7.6875,-7.667969 L 22.706,14.95 22.191,14.6 19.400391,15 19.318359,16.662109 17.706,14.95 17.191,14.6 14.400391,15 14.318359,16.662109 12.706,14.95 12.191,14.6 Z" transform="matrix(1 0 0 1 384.57143 515.798)"/>
|
||||
<path inkscape:connector-curvature="0" style="fill:url(#linearGradient4370)" id="rect4176" d="m 16,14 c -1.108,0 -2,0.892 -2,2 0,1.108 0.892,2 2,2 1.108,0 2,-0.892 2,-2 0,-1.108 -0.892,-2 -2,-2 z m -5,0 c -1.108,0 -2,0.892 -2,2 0,1.108 0.892,2 2,2 1.108,0 2,-0.892 2,-2 0,-1.108 -0.892,-2 -2,-2 z m 10,0 c -1.108,0 -2,0.892 -2,2 0,1.108 0.892,2 2,2 1.108,0 2,-0.892 2,-2 0,-1.108 -0.892,-2 -2,-2 z" transform="matrix(1 0 0 1 384.57143 515.798)"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 665 B |
|
@ -1 +1,18 @@
|
|||
<?xml version="1.0" ?><svg height="24" version="1.1" width="24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><g transform="translate(0 -1028.4)"><path d="m2 20v1c0 1.105 0.8954 2 2 2h2 12 2c1.105 0 2-0.895 2-2v-1h-20z" fill="#c0392b" transform="translate(0 1028.4)"/><g fill="#e74c3c"><rect height="6" width="12" x="6" y="1044.4"/><rect height="7" width="12" x="6" y="1029.4"/><rect height="10" width="12" x="6" y="1035.4"/><rect height="21" transform="translate(0 1028.4)" width="12" x="6" y="1"/></g><path d="m5 22 0.3397-20.196 17.32 10.392z" fill="#ecf0f1" transform="matrix(.28312 0 0 .29709 8.5844 1036.8)"/><path d="m4 1029.4c-1.1046 0-2 0.9-2 2v3 11 3c0 1.1 0.8954 2 2 2h2v-3-15-3h-2zm-0.5 2h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5zm0 3h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5zm0 3h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5zm0 3h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5zm0 3h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5zm0 3h1c0.2761 0 0.5 0.2 0.5 0.5v1c0 0.2-0.2239 0.5-0.5 0.5h-1c-0.2761 0-0.5-0.3-0.5-0.5v-1c0-0.3 0.2239-0.5 0.5-0.5z" fill="#c0392b"/><path d="m20 1029.4c1.105 0 2 0.9 2 2v3 11 3c0 1.1-0.895 2-2 2h-2v-3-15-3h2zm0.5 2h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5zm0 3h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5zm0 3h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5zm0 3h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5zm0 3h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5zm0 3h-1c-0.276 0-0.5 0.2-0.5 0.5v1c0 0.2 0.224 0.5 0.5 0.5h1c0.276 0 0.5-0.3 0.5-0.5v-1c0-0.3-0.224-0.5-0.5-0.5z" fill="#c0392b"/></g></svg>
|
||||
<svg width="32" xmlns="http://www.w3.org/2000/svg" height="32">
|
||||
<defs>
|
||||
<linearGradient id="a" y1="394.54" y2="325.98" gradientUnits="userSpaceOnUse" x2="0" gradientTransform="matrix(.48276 0 0 .40835 384.64 384.68)">
|
||||
<stop stop-color="#ffffff" stop-opacity="0"/>
|
||||
<stop offset="1" stop-color="#ffffff" stop-opacity=".2"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<g color-rendering="auto" color-interpolation-filters="linearRGB" shape-rendering="auto" image-rendering="auto" text-rendering="auto" color-interpolation="sRGB" color="#000000" transform="translate(-384.57-515.8)">
|
||||
<path fill="#db3333" d="m414.57 545.8h-28v-22h28v7z"/>
|
||||
<rect x="386.57" y="544.8" fill-opacity=".294" width="28" fill="#2e3132" height="1"/>
|
||||
<g fill="#ffffff">
|
||||
<rect x="386.57" y="523.8" fill-opacity=".41" width="28" height="1"/>
|
||||
<path opacity=".75" d="m387.57 525.8v2h2v-2zm24 0v2h2v-2zm-24 4v2h2v-2zm24 0v2h2v-2zm-24 4v2h2v-2zm24 0v2h2v-2zm-24 4v2h2v-2zm24 0v2h2v-2zm-24 4v2h2v-2zm24 0v2h2v-2z"/>
|
||||
<path opacity=".75" d="m405.55 527.8v2.821c-2.88.049-3.588 2.796-3.588 2.796h2.172v2.821h-3.368c-2.026 6.111-6.688 5.567-6.688 5.567v-2.821c0 0 2.958.537 4.467-4.849 1.887-6.737 7-6.334 7-6.334"/>
|
||||
</g>
|
||||
<path fill="url(#a)" d="m386.57 523.8v22h28v-22z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 1.2 KiB |
|
@ -1 +0,0 @@
|
|||
<?xml version="1.0" ?><svg height="24" version="1.1" width="24" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><g transform="translate(0 -1028.4)"><g fill="#2980b9"><path d="m12 1039.4c-3.0105 0-5.2407 0.1-6.7256 0.2-0.4788 0.1-0.9101 0.3-1.2672 0.6-0.357 0.3-0.6012 0.7-0.7148 1.1-0.211 0.9-0.2924 2.2-0.2924 4 0 1.9 0.0814 3.2 0.2924 4.1 0.1055 0.5 0.3578 0.8 0.7148 1.2 0.3652 0.3 0.764 0.5 1.2347 0.5 1.493 0.2 3.7476 0.3 6.7581 0.3 3.01 0 5.265-0.1 6.758-0.3 0.471 0 0.91-0.2 1.267-0.5 0.357-0.4 0.569-0.7 0.683-1.2 0.211-0.9 0.292-2.2 0.292-4.1 0-1.8-0.081-3.1-0.292-4-0.106-0.4-0.318-0.8-0.683-1.1-0.357-0.3-0.796-0.5-1.267-0.6-1.493-0.1-3.748-0.2-6.758-0.2z" fill="#c0392b"/><path d="m12 1038.4c-3.0105 0-5.2407 0.1-6.7256 0.2-0.4788 0.1-0.9101 0.3-1.2672 0.6-0.357 0.3-0.6012 0.7-0.7148 1.1-0.211 0.9-0.2924 2.2-0.2924 4 0 1.9 0.0814 3.2 0.2924 4.1 0.1055 0.5 0.3578 0.8 0.7148 1.2 0.3652 0.3 0.764 0.5 1.2347 0.5 1.493 0.2 3.7476 0.3 6.7581 0.3 3.01 0 5.265-0.1 6.758-0.3 0.471 0 0.91-0.2 1.267-0.5 0.357-0.4 0.569-0.7 0.683-1.2 0.211-0.9 0.292-2.2 0.292-4.1 0-1.8-0.081-3.1-0.292-4-0.106-0.4-0.318-0.8-0.683-1.1-0.357-0.3-0.796-0.5-1.267-0.6-1.493-0.1-3.748-0.2-6.758-0.2z" fill="#e74c3c"/><path d="m6.5 1l1.5 5v3h1v-3l1.5-5h-1l-1 3.3438-1-3.3438h-1zm6 2c-0.828 0-1.5 0.6716-1.5 1.5v3c0 0.8284 0.672 1.5 1.5 1.5s1.5-0.6716 1.5-1.5v-3c0-0.8284-0.672-1.5-1.5-1.5zm2.5 0v0.3438 1.6562 2.75c0 0.3821 0.036 0.664 0.094 0.8438 0.093 0.277 0.325 0.4063 0.656 0.4062 0.359 0.0001 0.869-0.2232 1.25-0.6875v0.25 0.4375h1v-6h-1v4.5 0.0938c-0.216 0.322-0.587 0.5-0.781 0.5-0.13 0-0.197-0.0852-0.219-0.25-0.007-0.015 0-0.1591 0-0.4063v-2.4375-1.6562-0.3438h-1zm-2.5 1c0.276 0 0.5 0.2239 0.5 0.5v3c0 0.2761-0.224 0.5-0.5 0.5s-0.5-0.2239-0.5-0.5v-3c0-0.2761 0.224-0.5 0.5-0.5z" fill="#202020" transform="translate(0 1028.4)"/><g fill="#ecf0f1"><rect height="1" width="4" x="4.5" y="1040.4"/><rect height="7" width="1" x="6" y="1041.4"/><path d="m8 1042.4v0.3 1.7 2.7c0 0.4 0.0362 0.7 0.0938 0.9 0.0934 0.2 0.3256 0.4 0.6562 0.4 0.3594 0 0.8691-0.3 1.25-0.7v0.2 0.5h1v-6h-1v4.5 0.1c-0.2156 0.3-0.5872 0.5-0.7812 0.5-0.1294 0-0.1972-0.1-0.2188-0.3-0.0072 0 0-0.2 0-0.4v-2.4-1.7-0.3h-1z"/><path d="m12 12v2 6h1v-0.438-0.25c0.381 0.465 0.891 0.688 1.25 0.688 0.331 0 0.563-0.129 0.656-0.406 0.058-0.18 0.094-0.462 0.094-0.844v-1.75-1.75c0-0.382-0.036-0.664-0.094-0.844-0.093-0.277-0.325-0.406-0.656-0.406-0.359 0-0.869 0.223-1.25 0.688v-0.688-2h-1zm1.781 2.906c0.13 0 0.197 0.085 0.219 0.25 0.007 0.015 0 0.159 0 0.406v1.438 1.438c0 0.247 0.007 0.391 0 0.406-0.022 0.165-0.089 0.25-0.219 0.25-0.194 0-0.565-0.178-0.781-0.5v-0.094-3.094c0.216-0.322 0.587-0.5 0.781-0.5z" transform="translate(0 1028.4)"/><path d="m17.5 14c-0.828 0-1.5 0.672-1.5 1.5v3c0 0.828 0.672 1.5 1.5 1.5s1.5-0.672 1.5-1.5v-0.5h-1v0.5c0 0.276-0.224 0.5-0.5 0.5s-0.5-0.224-0.5-0.5v-0.5-1h1 1v-1.5c0-0.828-0.672-1.5-1.5-1.5zm0 1c0.276 0 0.5 0.224 0.5 0.5v0.5h-1v-0.5c0-0.276 0.224-0.5 0.5-0.5z" transform="translate(0 1028.4)"/></g></g></g></svg>
|
Before Width: | Height: | Size: 3.1 KiB |