Compare commits

...

8 Commits

Author SHA1 Message Date
Martchus 3e243750a0 Avoid CMake deprecation warning by bumping version 2023-07-23 21:09:45 +02:00
Martchus ec0dda2677 Clarify licensing of icons similar to other projects
* Use fallback icons from Breeze project with according notice
* Replace program icon with one from Breeze as well as the origin of the
  program icon isn't clear anymore at this point
* Remove unused icons
* Add notice in README and about dialog
2022-09-10 16:37:52 +02:00
Martchus 55deda90ff Add copyright notice 2022-04-05 20:20:14 +02:00
Martchus 7db4e0bc56 Clarify that license is "GPL-2-or-later" 2022-03-15 21:48:21 +01:00
Martchus e4c5b23546 Fix typos found via `codespell --skip .git -w` 2021-07-03 19:54:06 +02:00
Martchus 5e42ba07ca Remove overspecification of Qt version in documentation and comments 2020-09-04 01:14:36 +02:00
Martchus 884bed480d Support Qt 6 (commit 174154b) 2020-09-04 00:57:42 +02:00
Martchus 8d09b4e308 Add 256x256 application icon 2020-08-11 23:25:20 +02:00
31 changed files with 405 additions and 149 deletions

View File

@ -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)
@ -11,7 +11,7 @@ set(META_APP_URL "https://github.com/${META_APP_AUTHOR}/${META_PROJECT_NAME}")
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 6)
set(META_VERSION_PATCH 7)
# add project files
set(HEADER_FILES
@ -146,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

212
LICENSE.LESSER Normal file
View File

@ -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.

View File

@ -1,12 +1,12 @@
# Video Downloader
A video downloader with Qt 5 GUI and backends for multiple platforms, e.g. YouTube and
A video downloader with Qt GUI and backends for multiple platforms, e.g. YouTube and
Vimeo.
---
**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 5 showing the progress and speed in a list view.
downloads with Qt showing the progress and speed in a list view.
---
@ -23,6 +23,14 @@ by YouTube which currently need to be downloaded separately and then muxed toget
## Build instructions
The video downloader depends on c++utilities and qtutilities and is built in the same
way as these libaries.
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.

View 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()) {

View File

@ -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
@ -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?"));

View File

@ -195,8 +195,12 @@ MainWindow::~MainWindow()
void MainWindow::showAboutDialog()
{
if (!m_aboutDlg) {
m_aboutDlg = new AboutDialog(this, QStringLiteral(APP_URL),
tr("Simple video downloader with Qt GUI and backends for multiple platforms, e.g. YouTube and Vimeo."),
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()) {
@ -339,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:
@ -474,7 +478,7 @@ 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) {
@ -482,7 +486,7 @@ void MainWindow::updateStartStopControls()
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);
QStringList lines = data.split(QChar('\n'), Qt::SkipEmptyParts);
for (const QString &line : lines) {
if (Download *download = Download::fromUrl(line)) {
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."));
}
}
@ -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));
}

View File

@ -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);
@ -406,13 +406,13 @@ 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;
@ -422,7 +422,7 @@ SettingsDialog::SettingsDialog(QWidget *parent)
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()

View File

@ -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.
@ -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)
@ -429,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)
{
@ -612,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)
{
@ -802,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:
@ -833,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)
{
@ -940,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.

View File

@ -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
{

View File

@ -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"),

View File

@ -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. */
};

View File

@ -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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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()) {

View File

@ -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();
}

View File

@ -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

View File

@ -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);
QStringList completeFields = videoInfo.split(QChar('&'), Qt::SkipEmptyParts, Qt::CaseSensitive);
for (const QString &completeField : completeFields) {
QStringList fieldParts = completeField.split(QChar('='), QString::SkipEmptyParts, Qt::CaseSensitive);
QStringList fieldParts = completeField.split(QChar('='), Qt::SkipEmptyParts, Qt::CaseSensitive);
if (fieldParts.count() < 2) {
continue;
}
@ -93,13 +93,13 @@ void YoutubeDownload::evalVideoInformation(Download *, QBuffer *videoInfoBuffer)
for (const QString &fmtFieldId : fmtFieldIds) {
QString fmtField = m_fields.value(fmtFieldId, QString());
if (!fmtField.isEmpty()) {
QStringList sections = fmtField.split(QChar(','), QString::SkipEmptyParts, Qt::CaseSensitive);
QStringList sections = fmtField.split(QChar(','), Qt::SkipEmptyParts, Qt::CaseSensitive);
for (const QString &section : sections) {
QStringList fmtParts = section.split(QChar('&'), QString::SkipEmptyParts, Qt::CaseSensitive);
QStringList fmtParts = section.split(QChar('&'), Qt::SkipEmptyParts, Qt::CaseSensitive);
QString itag, urlPart1, urlPart2, name;
QJsonObject itagObj;
for (const QString fmtPart : fmtParts) {
QStringList fmtSubParts = fmtPart.split(QChar('='), QString::SkipEmptyParts, Qt::CaseSensitive);
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(' '))));
}
}
}

View File

@ -1,7 +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/applications-internet.svg</file>
<file>icons/hicolor/32x32/categories/preferences-other.svg</file>
</qresource>
</RCC>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

View File

@ -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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

View File

@ -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

View File

@ -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

View File

@ -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