11// SPDX-License-Identifier: Apache-2.0
22
3+ #include < scratchcpp/costume.h>
4+ #include < scratchcpp/sound.h>
35#include < iostream>
46
57#include " project_p.h"
68#include " internal/scratch3reader.h"
9+ #include " internal/projectdownloaderfactory.h"
10+ #include " internal/projectdownloader.h"
11+ #include " internal/projecturl.h"
712#include " engine/internal/engine.h"
813
914using namespace libscratchcpp ;
1015
16+ IProjectDownloaderFactory *ProjectPrivate::downloaderFactory = nullptr ;
17+
1118ProjectPrivate::ProjectPrivate () :
1219 engine(std::make_shared<Engine>())
1320{
21+ if (!downloaderFactory)
22+ downloaderFactory = ProjectDownloaderFactory::instance ().get ();
23+
24+ downloader = downloaderFactory->create ();
1425}
1526
1627ProjectPrivate::ProjectPrivate (const std::string &fileName) :
17- fileName(fileName),
18- engine(std::make_shared<Engine>())
28+ ProjectPrivate()
1929{
20- // Auto detect Scratch version
21- scratchVersion = ScratchVersion::Invalid;
22- Scratch3Reader scratch3;
23- scratch3.setFileName (fileName);
24- if (scratch3.isValid ())
25- scratchVersion = ScratchVersion::Scratch3;
30+ this ->fileName = fileName;
2631
27- if (scratchVersion == ScratchVersion::Invalid)
28- std::cerr << " Unable to determine Scratch version. " << std::endl ;
32+ // Auto detect Scratch version
33+ detectScratchVersion () ;
2934}
3035
3136ProjectPrivate::ProjectPrivate (const std::string &fileName, ScratchVersion scratchVersion) :
@@ -47,16 +52,77 @@ bool ProjectPrivate::load()
4752 break ;
4853 }
4954
50- reader->setFileName (fileName);
51- if (!reader->isValid ()) {
52- scratchVersion = ScratchVersion::Invalid;
53- std::cerr << " Could not read the project." << std::endl;
54- return false ;
55- }
55+ // Load from URL
56+ ProjectUrl url (fileName);
57+
58+ if (url.isProjectUrl ()) {
59+ // Download JSON
60+ if (!downloader->downloadJson (url.projectId ())) {
61+ std::cerr << " Failed to download the project file." << std::endl;
62+ return false ;
63+ }
64+
65+ bool ret = reader->loadData (downloader->json ());
66+
67+ if (!ret)
68+ return false ;
69+
70+ // Get asset file names
71+ std::vector<std::string> assetNames;
72+ std::unordered_map<std::string, Asset *> assets;
73+ const auto &targets = reader->targets ();
74+
75+ for (auto target : targets) {
76+ const auto &costumes = target->costumes ();
77+ const auto &sounds = target->sounds ();
78+
79+ for (auto costume : costumes) {
80+ auto it = std::find (assetNames.begin (), assetNames.end (), costume->fileName ());
81+ if (it == assetNames.end ()) {
82+ assetNames.push_back (costume->fileName ());
83+ assets[assetNames.back ()] = costume.get ();
84+ } else
85+ assets[*it] = costume.get ();
86+ }
87+
88+ for (auto sound : sounds) {
89+ auto it = std::find (assetNames.begin (), assetNames.end (), sound->fileName ());
90+ if (it == assetNames.end ()) {
91+ assetNames.push_back (sound->fileName ());
92+ assets[assetNames.back ()] = sound.get ();
93+ } else
94+ assets[*it] = sound.get ();
95+ }
96+ }
97+
98+ // Download assets
99+ if (!downloader->downloadAssets (assetNames)) {
100+ std::cerr << " Failed to download the project assets." << std::endl;
101+ return false ;
102+ }
56103
57- bool ret = reader->load ();
58- if (!ret)
59- return false ;
104+ const auto &assetData = downloader->assets ();
105+ assert (assetData.size () == assetNames.size ());
106+
107+ // Load asset data
108+ for (size_t i = 0 ; i < assets.size (); i++) {
109+ const std::string &data = assetData[i];
110+ assets[assetNames[i]]->setData (data.size (), static_cast <void *>(const_cast <char *>(data.c_str ())));
111+ }
112+
113+ } else {
114+ // Load from file
115+ reader->setFileName (fileName);
116+ if (!reader->isValid ()) {
117+ scratchVersion = ScratchVersion::Invalid;
118+ std::cerr << " Could not read the project." << std::endl;
119+ return false ;
120+ }
121+
122+ bool ret = reader->load ();
123+ if (!ret)
124+ return false ;
125+ }
60126
61127 engine->clear ();
62128 engine->setTargets (reader->targets ());
@@ -81,6 +147,30 @@ void ProjectPrivate::runEventLoop()
81147 engine->runEventLoop ();
82148}
83149
150+ void ProjectPrivate::detectScratchVersion ()
151+ {
152+ ProjectUrl url (fileName);
153+
154+ scratchVersion = ScratchVersion::Invalid;
155+ Scratch3Reader scratch3;
156+
157+ if (url.isProjectUrl ()) {
158+ if (!downloader->downloadJson (url.projectId ())) {
159+ std::cerr << " Failed to download the project file." << std::endl;
160+ return ;
161+ }
162+
163+ scratch3.loadData (downloader->json ());
164+ } else
165+ scratch3.setFileName (fileName);
166+
167+ if (scratch3.isValid ())
168+ scratchVersion = ScratchVersion::Scratch3;
169+
170+ if (scratchVersion == ScratchVersion::Invalid)
171+ std::cerr << " Unable to determine Scratch version." << std::endl;
172+ }
173+
84174void ProjectPrivate::setScratchVersion (ScratchVersion version)
85175{
86176 // TODO: Use this when more versions become supported
@@ -90,3 +180,8 @@ void ProjectPrivate::setScratchVersion(ScratchVersion version)
90180 else
91181 std::cerr << " Unsupported Scratch version: " << static_cast <int >(version) << std::endl;
92182}
183+
184+ void ProjectPrivate::setDownloadProgressCallback (const std::function<void (unsigned int , unsigned int )> &f)
185+ {
186+ downloader->setDownloadProgressCallback (f);
187+ }
0 commit comments