Skip to content

Commit

Permalink
Recovery Mode (#915)
Browse files Browse the repository at this point in the history
* Shared - Make Models JSON Serializable and Deserializable

* Update yt-dlp

* Shared - Implement Recovery Mode

* Shared - Show Recovered Downloads Notification

* UI - Add `Recover Crashed Downloads` Preference Option

* GNOME - Add `shield-warning-symbolic` Icon

* Shared - Listen to `Recover Crashed Downloads` Option
  • Loading branch information
nlogozzo authored Oct 22, 2024
1 parent 2253279 commit 0991081
Show file tree
Hide file tree
Showing 66 changed files with 4,111 additions and 3,183 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
working-directory: ${{github.workspace}}/inno
run: |
powershell -command "Invoke-WebRequest https://aka.ms/vs/17/release/vc_redist.x64.exe -OutFile vc_redist.x64.exe"
powershell -command "Invoke-WebRequest https://github.com/yt-dlp/yt-dlp/releases/download/2024.10.07/yt-dlp.exe -OutFile yt-dlp.exe"
powershell -command "Invoke-WebRequest https://github.com/yt-dlp/yt-dlp/releases/download/2024.10.22/yt-dlp.exe -OutFile yt-dlp.exe"
powershell -command "Invoke-WebRequest https://github.com/aria2/aria2/releases/download/release-1.37.0/aria2-1.37.0-win-64bit-build1.zip -OutFile aria2.zip"
powershell -command "Invoke-WebRequest https://github.com/GyanD/codexffmpeg/releases/download/7.1/ffmpeg-7.1-full_build.zip -OutFile ffmpeg.zip"
powershell -command "Expand-Archive -Force 'aria2.zip'"
Expand Down
10 changes: 5 additions & 5 deletions flatpak/python3-modules.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "python3-yt-dlp",
"buildsystem": "simple",
"build-commands": [
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"yt-dlp\" --no-build-isolation"
"pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"yt-dlp[default]\" --no-build-isolation"
],
"sources": [
{
Expand All @@ -17,8 +17,8 @@
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/63/09/c1bc53dab74b1816a00d8d030de5bf98f724c52c1635e07681d312f20be8/charset-normalizer-3.3.2.tar.gz",
"sha256": "f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"
"url": "https://files.pythonhosted.org/packages/f2/4f/e1808dc01273379acc506d18f1504eb2d299bd4131743b9fc54d7be4df1e/charset_normalizer-3.4.0.tar.gz",
"sha256": "223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"
},
{
"type": "file",
Expand Down Expand Up @@ -52,8 +52,8 @@
},
{
"type": "file",
"url": "https://files.pythonhosted.org/packages/6e/91/ecb07d66110334cdb01e94b187577af3b041897090203c9957728825d46f/yt_dlp-2024.10.7-py3-none-any.whl",
"sha256": "9e336ae663bfd7ad3ea1c02e722747388172719efc0fc39a807dace3073aa704"
"url": "https://files.pythonhosted.org/packages/bb/68/548f9819b41d53561d4f3d39588111cf39993c066b6e5300b4ae118eb2e6/yt_dlp-2024.10.22-py3-none-any.whl",
"sha256": "ba166602ebe22a220e4dc1ead45bf00eb469ed812b22f4fb8bb54734f9b02084"
}
]
}
1 change: 1 addition & 0 deletions libparabolic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ add_library(libparabolic
"src/models/downloadhistory.cpp"
"src/models/downloadmanager.cpp"
"src/models/downloadoptions.cpp"
"src/models/downloadrecoveryqueue.cpp"
"src/models/format.cpp"
"src/models/historicdownload.cpp"
"src/models/media.cpp"
Expand Down
5 changes: 5 additions & 0 deletions libparabolic/include/models/download.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return The url of the download
*/
const std::string& getUrl() const;
/**
* @brief Gets the options of the download.
* @return The options of the download
*/
const DownloadOptions& getOptions() const;
/**
* @brief Gets the status of the download.
* @return The status of the download
Expand Down
12 changes: 12 additions & 0 deletions libparabolic/include/models/downloaderoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <filesystem>
#include <string>
#include <boost/json.hpp>
#include "browser.h"
#include "videocodec.h"

Expand Down Expand Up @@ -69,6 +70,16 @@ namespace Nickvision::TubeConverter::Shared::Models
* @param codec The new preferred video codec
*/
void setPreferredVideoCodec(VideoCodec codec);
/**
* @brief Gets whether or not to recover crashed downloads.
* @return True to recover crashed downloads, else false
*/
bool getRecoverCrashedDownloads() const;
/**
* @brief Sets whether or not to recover crashed downloads.
* @param recoverCrashedDownloads True to recover crashed downloads, else false
*/
void setRecoverCrashedDownloads(bool recoverCrashedDownloads);
/**
* @brief Gets whether or not to use aria2 for downloading.
* @return True to use aria2, else false
Expand Down Expand Up @@ -230,6 +241,7 @@ namespace Nickvision::TubeConverter::Shared::Models
bool m_limitCharacters;
bool m_includeAutoGeneratedSubtitles;
VideoCodec m_preferredVideoCodec;
bool m_recoverCrashedDownloads;
bool m_useAria;
int m_ariaMaxConnectionsPerServer;
int m_ariaMinSplitSize;
Expand Down
8 changes: 6 additions & 2 deletions libparabolic/include/models/downloadmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "download.h"
#include "downloaderoptions.h"
#include "downloadhistory.h"
#include "downloadrecoveryqueue.h"
#include "urlinfo.h"
#include "events/downloadaddedeventargs.h"
#include "events/downloadcompletedeventargs.h"
Expand All @@ -33,7 +34,7 @@ namespace Nickvision::TubeConverter::Shared::Models
* @param history The DownloadHistory
* @param logger The Logger
*/
DownloadManager(const DownloaderOptions& options, DownloadHistory& history, Logging::Logger& logger);
DownloadManager(const DownloaderOptions& options, DownloadHistory& history, DownloadRecoveryQueue& recoveryQueue, Logging::Logger& logger);
/**
* @brief Destructs a DownloadManager.
*/
Expand Down Expand Up @@ -124,8 +125,10 @@ namespace Nickvision::TubeConverter::Shared::Models
/**
* @brief Loads the download history.
* @brief This method invokes the historyChanged event.
* @brief This method will recover previous downloads that were interrupted by a crash.
* @brief Returns the number of downloads recovered.
*/
void loadHistory();
size_t startup();
/**
* @brief Clears the download history.
* @brief This method invokes the historyChanged event.
Expand Down Expand Up @@ -209,6 +212,7 @@ namespace Nickvision::TubeConverter::Shared::Models
mutable std::mutex m_mutex;
DownloaderOptions m_options;
DownloadHistory& m_history;
DownloadRecoveryQueue& m_recoveryQueue;
Logging::Logger& m_logger;
std::unordered_map<int, std::shared_ptr<Download>> m_downloading;
std::unordered_map<int, std::shared_ptr<Download>> m_queued;
Expand Down
11 changes: 11 additions & 0 deletions libparabolic/include/models/downloadoptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <optional>
#include <string>
#include <vector>
#include <boost/json.hpp>
#include <libnick/keyring/credential.h>
#include "downloaderoptions.h"
#include "format.h"
Expand All @@ -31,6 +32,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @param url The URL of the download
*/
DownloadOptions(const std::string& url);
/**
* @brief Construct a DownloadOptions.
* @param json The JSON object to construct the DownloadOptions from
*/
DownloadOptions(boost::json::object json);
/**
* @brief Gets the URL of the download.
* @return The URL of the download
Expand Down Expand Up @@ -159,6 +165,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return The vector of yt-dlp arguments
*/
std::vector<std::string> toArgumentVector(const DownloaderOptions& downloaderOptions) const;
/**
* @brief Converts the DownloadOptions to a JSON object.
* @return The JSON object
*/
boost::json::object toJson() const;

private:
/**
Expand Down
53 changes: 53 additions & 0 deletions libparabolic/include/models/downloadrecoveryqueue.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#ifndef DOWNLOADRECOVERYQUEUE_H
#define DOWNLOADRECOVERYQUEUE_H

#include <unordered_map>
#include <libnick/app/datafilebase.h>
#include "downloadoptions.h"

namespace Nickvision::TubeConverter::Shared::Models
{
class DownloadRecoveryQueue : public Nickvision::App::DataFileBase
{
public:
/**
* @brief Constructs a DownloadRecoveryQueue.
* @brief This will load the recoverable downloads from disk.
* @param key The key to pass to the DataFileBase
* @param appName The name of the application to pass to the DataFileBase
*/
DownloadRecoveryQueue(const std::string& key, const std::string& appName);
/**
* @brief Gets a list of downloads to recover.
* @returns A list of DownloadOptions
*/
const std::unordered_map<int, DownloadOptions>& getRecoverableDownloads() const;
/**
* @brief Adds a download to the recovery queue.
* @param id The ID of the download
* @param downloadOptions The options of the download
* @returns True if added, else false
*/
bool addDownload(int id, const DownloadOptions& downloadOptions);
/**
* @brief Removes a download from the recovery queue.
* @param id The ID of the download
* @returns True if removed, else false
*/
bool removeDownload(int id);
/**
* @brief Clears all downloads from the recovery queue.
* @returns True if cleared, else false
*/
bool clear();

private:
/**
* Updates the recovery file on disk.
*/
void updateDisk();
std::unordered_map<int, DownloadOptions> m_recoverableDownloads;
};
}

#endif //DOWNLOADRECOVERYQUEUE_H
11 changes: 9 additions & 2 deletions libparabolic/include/models/format.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,10 @@ namespace Nickvision::TubeConverter::Shared::Models
public:
/**
* @brief Constructs a Format.
* @param format The yt-dlp format json object
* @param json The JSON object to construct the Format from
* @param isYtdlpJson Whether or not the json object is in yt-dlp json format
*/
Format(boost::json::object format);
Format(boost::json::object json, bool isYtdlpJson = true);
/**
* @brief Gets the id of the format.
* @return The id of the format
Expand Down Expand Up @@ -66,6 +67,12 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return The audio bitrate of the format
*/
const std::optional<double>& getAudioBitrate() const;
/**
* @brief Converts the Format to a JSON object.
* @brief The json object will not be in yt-dlp json format.
* @return The JSON object
*/
boost::json::object toJson() const;

private:
std::string m_id;
Expand Down
11 changes: 11 additions & 0 deletions libparabolic/include/models/subtitlelanguage.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define SUBTITLELANGUAGE_H

#include <string>
#include <boost/json.hpp>

namespace Nickvision::TubeConverter::Shared::Models
{
Expand All @@ -17,6 +18,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @param isAutoGenerated Whether or not the subtitle is auto-generated
*/
SubtitleLanguage(const std::string& language, bool isAutoGenerated = false);
/**
* @brief Constructs a SubtitleLanguage.
* @param json The JSON object to construct the SubtitleLanguage from
*/
SubtitleLanguage(boost::json::object json);
/**
* @brief Gets the language of the subtitle.
* @return The language of the subtitle
Expand All @@ -32,6 +38,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return A string representation of the subtitle language
*/
std::string str() const;
/**
* @brief Converts the SubtitleLanguage to a JSON object.
* @return The JSON object
*/
boost::json::object toJson() const;
/**
* @brief Compares two SubtitleLanguages via ==.
* @param other The other SubtitleLanguage to compare
Expand Down
11 changes: 11 additions & 0 deletions libparabolic/include/models/timeframe.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <chrono>
#include <optional>
#include <string>
#include <boost/json.hpp>

namespace Nickvision::TubeConverter::Shared::Models
{
Expand All @@ -20,6 +21,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @throw std::invalid_argument Thrown if the end time is before the start time
*/
TimeFrame(const std::chrono::seconds& start, const std::chrono::seconds& end);
/**
* @brief Constructs a TimeFrame.
* @param json The JSON object to construct the TimeFrame from
*/
TimeFrame(boost::json::object json);
/**
* @brief Parses a TimeFrame from start and end time strings.
* @param start The start time string in the format "HH:MM:SS"
Expand Down Expand Up @@ -71,6 +77,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return The string representation of the end time
*/
std::string endStr() const;
/**
* @brief Converts the TimeFrame to a JSON object.
* @return The JSON object representation of the TimeFrame
*/
boost::json::object toJson() const;
/**
* @brief Compares two TimeFrames via ==.
* @param other The other TimeFrame to compare
Expand Down
11 changes: 11 additions & 0 deletions libparabolic/include/models/videoresolution.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

#include <optional>
#include <string>
#include <boost/json.hpp>

namespace Nickvision::TubeConverter::Shared::Models
{
Expand All @@ -23,6 +24,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @param height The height of the resolution
*/
VideoResolution(int width, int height);
/**
* @brief Constructs a VideoResolution.
* @param json The JSON object to construct the VideoResolution from
*/
VideoResolution(boost::json::object json);
/**
* @brief Parses a VideoResolution from a string.
* @param value The string to parse (Format: "WidthxHeight")
Expand Down Expand Up @@ -54,6 +60,11 @@ namespace Nickvision::TubeConverter::Shared::Models
* @return The string representation of the resolution
*/
std::string str() const;
/**
* @brief Converts the VideoResolution to a JSON object.
* @return The JSON object
*/
boost::json::object toJson() const;
/**
* @brief Compares two VideoResolutions via ==.
* @param other The other VideoResolution to compare
Expand Down
14 changes: 9 additions & 5 deletions libparabolic/src/controllers/mainwindowcontroller.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
#include <sstream>
#include <thread>
#include <libnick/filesystem/userdirectories.h>
#include <libnick/helpers/codehelpers.h>
#include <libnick/helpers/stringhelpers.h>
#include <libnick/localization/documentation.h>
#include <libnick/localization/gettext.h>
#include <libnick/system/environment.h>
#include "models/configuration.h"
#include "models/downloadhistory.h"
#include "models/downloadrecoveryqueue.h"
#include "models/previousdownloadoptions.h"
#ifdef _WIN32
#include <windows.h>
Expand All @@ -36,12 +36,12 @@ namespace Nickvision::TubeConverter::Shared::Controllers
m_dataFileManager{ m_appInfo.getName() },
m_logger{ UserDirectories::get(ApplicationUserDirectory::LocalData, m_appInfo.getName()) / "log.txt", Logging::LogLevel::Info, false },
m_keyring{ m_appInfo.getId() },
m_downloadManager{ m_dataFileManager.get<Configuration>("config").getDownloaderOptions(), m_dataFileManager.get<DownloadHistory>("history"), m_logger }
m_downloadManager{ m_dataFileManager.get<Configuration>("config").getDownloaderOptions(), m_dataFileManager.get<DownloadHistory>("history"), m_dataFileManager.get<DownloadRecoveryQueue>("recovery"), m_logger }
{
m_appInfo.setVersion({ "2024.10.3-next" });
m_appInfo.setShortName(_("Parabolic"));
m_appInfo.setDescription(_("Download web video and audio"));
m_appInfo.setChangelog("- Added support for selecting a batch file with multiple URLs to validate instead of validating a single URL at a time\n- Fixed an issue where UTF-8 characters were not displayed correctly on Windows\n- Fixed an issue where playlist names were not normalized on Windows\n- Fixed an issue where the row animations were choppy using aria2c on Linux\n- Fixed an issue where the app would crash when stopping all downloads on Linux");
m_appInfo.setChangelog("- Added support for selecting a batch file with multiple URLs to validate instead of validating a single URL at a time\n- Added a recovery mode where downloads that were running/queued will be restored when the application is restarted after a crash\n- Fixed an issue where UTF-8 characters were not displayed correctly on Windows\n- Fixed an issue where playlist names were not normalized on Windows\n- Fixed an issue where the row animations were choppy using aria2c on Linux\n- Fixed an issue where the app would crash when stopping all downloads on Linux");
m_appInfo.setSourceRepo("https://github.com/NickvisionApps/Parabolic");
m_appInfo.setIssueTracker("https://github.com/NickvisionApps/Parabolic/issues/new");
m_appInfo.setSupportUrl("https://github.com/NickvisionApps/Parabolic/discussions");
Expand Down Expand Up @@ -239,8 +239,12 @@ namespace Nickvision::TubeConverter::Shared::Controllers
m_logger.log(Logging::LogLevel::Error, "Unable to connect to Linux taskbar.");
}
#endif
//Load history
m_downloadManager.loadHistory();
//Load DownloadManager
size_t recoveredDownloads{ m_downloadManager.startup() };
if(recoveredDownloads > 0)
{
m_notificationSent.invoke({ std::vformat(_n("Recovered {} download", "Recovered {} downloads", recoveredDownloads), std::make_format_args(recoveredDownloads)), NotificationSeverity::Informational });
}
//Check if disclaimer should be shown
if(m_dataFileManager.get<Configuration>("config").getShowDisclaimerOnStartup())
{
Expand Down
Loading

0 comments on commit 0991081

Please sign in to comment.