Skip to content

Commit 415b42d

Browse files
authored
Merge pull request #767 from hiscoder-com/develop
Develop
2 parents 7221c28 + d3ec3ea commit 415b42d

4 files changed

Lines changed: 170 additions & 36 deletions

File tree

components/Project/Download.js

Lines changed: 115 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import ButtonLoading from 'components/ButtonLoading'
1515
import CheckBox from 'components/CheckBox'
1616
import ListBox from 'components/ListBox'
1717

18-
import { newTestamentList, usfmFileNames } from 'utils/config'
18+
import { newTestamentList, obsStoryVerses, usfmFileNames } from 'utils/config'
1919
import {
2020
compileChapter,
2121
convertToUsfm,
@@ -60,7 +60,10 @@ function Download({
6060
switch (project?.type) {
6161
case 'obs':
6262
if (isBook) {
63-
extraOptions = [{ label: 'ZIP', value: 'zip' }]
63+
extraOptions = [
64+
{ label: 'ZIP', value: 'zip' },
65+
{ label: t('projects:Project'), value: 'project' },
66+
]
6467
} else {
6568
extraOptions = [{ label: 'Markdown', value: 'markdown' }]
6669
}
@@ -203,29 +206,45 @@ function Download({
203206
: t('books:' + bookCode),
204207
},
205208
]
206-
const createChapters = async (bookLink) => {
209+
const createChapters = async (bookLink, typeProject) => {
207210
if (!bookLink) return null
208-
209-
const { data: jsonChapterVerse, error: errorJsonChapterVerse } =
210-
await getCountChaptersAndVerses({
211-
link: bookLink,
212-
})
213-
if (errorJsonChapterVerse) {
214-
return null
211+
let chapterVerse = {}
212+
if (typeProject === 'obs') {
213+
chapterVerse = obsStoryVerses
214+
} else {
215+
const { data: jsonChapterVerse, error: errorJsonChapterVerse } =
216+
await getCountChaptersAndVerses({
217+
link: bookLink,
218+
})
219+
chapterVerse = jsonChapterVerse
220+
if (errorJsonChapterVerse) {
221+
return null
222+
}
215223
}
216224
const chapters = {}
217-
for (const chapterNum in jsonChapterVerse) {
218-
if (Object.hasOwnProperty.call(jsonChapterVerse, chapterNum)) {
219-
const verses = jsonChapterVerse[chapterNum]
225+
for (const chapterNum in chapterVerse) {
226+
if (Object.hasOwnProperty.call(chapterVerse, chapterNum)) {
227+
const verses = chapterVerse[chapterNum]
220228
const newVerses = {}
229+
230+
if (typeProject === 'obs') {
231+
newVerses[0] = { text: '', enabled: false, history: [] }
232+
}
233+
221234
for (let index = 1; index < verses + 1; index++) {
222235
newVerses[index] = { text: '', enabled: false, history: [] }
223236
}
237+
238+
if (typeProject === 'obs') {
239+
newVerses[200] = { text: '', enabled: false, history: [] }
240+
}
241+
224242
chapters[chapterNum] = newVerses
225243
}
226244
}
227245
return chapters
228246
}
247+
229248
const getResourcesUrls = async (resources) => {
230249
if (!resources) return null
231250
const urls = {}
@@ -235,6 +254,14 @@ function Download({
235254
if (resource === 'tAcademy') {
236255
continue
237256
}
257+
if (resource === 'obs') {
258+
const { owner, repo } = resources[resource]
259+
const url = ` ${
260+
process.env.NEXT_PUBLIC_NODE_HOST ?? 'https://git.door43.org'
261+
}/${owner}/${repo}/archive/master.zip`
262+
urls[resource] = url
263+
continue
264+
}
238265
const { owner, repo, commit, manifest } = resources[resource]
239266
const bookPath = manifest.projects.find((el) => el.identifier === bookCode)?.path
240267
const url = ` ${
@@ -265,7 +292,7 @@ function Download({
265292
try {
266293
const parts = url.split('/')
267294
const baseUrl = parts.slice(0, 3).join('/')
268-
const repo = parts[4].slice(0, -1)
295+
const repo = parts[4].split('_')[0] + '_tw'
269296
const owner = parts[3]
270297
const newUrl = `${baseUrl}/${owner}/${repo}/archive/master.zip`
271298
const response = await axios.get(newUrl, { responseType: 'arraybuffer' })
@@ -319,7 +346,13 @@ function Download({
319346
if (!chapters || !project) {
320347
return null
321348
}
322-
const initChapters = Object.keys(chapters).reduce((acc, chapter) => {
349+
350+
const sortedChapters = Object.fromEntries(
351+
Object.entries(chapters)
352+
.map(([key, value]) => [parseInt(key, 10), value])
353+
.sort(([a], [b]) => a - b)
354+
)
355+
const initChapters = Object.keys(sortedChapters).reduce((acc, chapter) => {
323356
acc[chapter] = 0
324357
return acc
325358
}, {})
@@ -338,25 +371,69 @@ function Download({
338371
book: { code: bookCode, name: bookName },
339372
resources: addResourceName(project.resources),
340373
mainResource: project.base_manifest.resource,
374+
typeProject: project.type,
375+
language: { is_rtl: project.is_rtl },
341376
}
342377
return JSON.stringify(config)
343378
}
344379

345-
const downloadResources = async (resourcesUrls, zip) => {
380+
const downloadResources = async (resourcesUrls, zip, typeProject) => {
346381
for (const resource in resourcesUrls) {
347-
if (Object.hasOwnProperty.call(resourcesUrls, resource)) {
348-
const url = resourcesUrls[resource]
349-
try {
382+
if (!Object.hasOwnProperty.call(resourcesUrls, resource)) continue
383+
384+
const url = resourcesUrls[resource]
385+
try {
386+
if (resource === 'obs') {
387+
const response = await axios.get(url, { responseType: 'arraybuffer' })
388+
if (response.status !== 200)
389+
throw new Error(`Failed to fetch OBS archive: ${url}`)
390+
391+
const obsZip = await JSZip.loadAsync(response.data)
392+
393+
const rootFolder = Object.keys(obsZip.files).find(
394+
(path) => obsZip.files[path].dir
395+
)
396+
if (!rootFolder) throw new Error('No root folder found in OBS archive')
397+
398+
const newObsZip = new JSZip()
399+
for (const filePath of Object.keys(obsZip.files)) {
400+
const file = obsZip.files[filePath]
401+
if (file.dir || !filePath.startsWith(rootFolder)) continue
402+
403+
const newPath = filePath.slice(rootFolder.length)
404+
const content = await file.async('nodebuffer')
405+
newObsZip.file(newPath, content)
406+
}
407+
408+
const newObsZipContent = await newObsZip.generateAsync({ type: 'nodebuffer' })
409+
zip.file('obs.zip', newObsZipContent)
410+
411+
const { data: obsImagesUrl } = await getOBSImages()
412+
if (!obsImagesUrl) throw new Error('OBS images URL is not defined')
413+
const responseObsImages = await axios.get(obsImagesUrl, {
414+
responseType: 'arraybuffer',
415+
})
416+
417+
if (responseObsImages.status !== 200)
418+
throw new Error(`Failed to fetch OBS images from storage: ${obsImagesUrl}`)
419+
420+
const obsImagesZip = await JSZip.loadAsync(responseObsImages.data)
421+
422+
const obsImagesZipContent = await obsImagesZip.generateAsync({
423+
type: 'nodebuffer',
424+
})
425+
zip.file('obs-images-360px.zip', obsImagesZipContent)
426+
} else {
350427
const response = await axios.get(url)
351428
if (response.status === 200) {
352429
const content = response.data
353430
zip.file(`${resource}.${url.split('.').pop()}`, content)
354431
} else {
355432
throw new Error(`Failed to fetch resource: ${url}`)
356433
}
357-
} catch (error) {
358-
console.error(`Error loading: ${url}`, error)
359434
}
435+
} catch (error) {
436+
console.error(`Error loading ${url}:`, error)
360437
}
361438
}
362439
}
@@ -382,6 +459,21 @@ function Download({
382459
zip.folder(foldername)
383460
})
384461
}
462+
const getOBSImages = async () => {
463+
try {
464+
const response = await axios.get(`/api/obs-images`)
465+
466+
if (response.status === 200) {
467+
const content = response.data
468+
return content
469+
} else {
470+
throw new Error(`Failed to fetch resource: ${url}`)
471+
}
472+
} catch (error) {
473+
console.error(`Error loading ${url}:`, error)
474+
return null
475+
}
476+
}
385477
const createOfflineProject = async (project, bookCode) => {
386478
try {
387479
const bookLink = project.base_manifest.books.find(
@@ -390,7 +482,7 @@ function Download({
390482
if (!bookLink) {
391483
throw new Error('Book link not found')
392484
}
393-
const chapters = await createChapters(bookLink)
485+
const chapters = await createChapters(bookLink, project.type)
394486
if (!chapters) {
395487
throw new Error('Chapters not created')
396488
}
@@ -401,7 +493,7 @@ function Download({
401493
if (!resourcesUrls) {
402494
throw new Error('Resource URLs not found')
403495
}
404-
await downloadResources(resourcesUrls, zip)
496+
await downloadResources(resourcesUrls, zip, project.type)
405497
const tWordsBuffer = await getTwords(resourcesUrls['twords'])
406498
if (!tWordsBuffer) {
407499
throw new Error('tWords not fetched')

components/StartPage/Download.js

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -53,32 +53,33 @@ function Download({ t, onClose }) {
5353
fetchVersion()
5454
}, [])
5555

56-
const getDownloadLink = () => {
56+
const getDownloadLink = (type) => {
5757
if (os.os === 'Windows') {
5858
return os.architecture === '64-bit'
59-
? `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-x64-${version}.exe`
60-
: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-ia32-${version}.exe`
59+
? `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-x64-${version}-${type}.exe`
60+
: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-ia32-${version}-${type}.exe`
6161
} else if (os.os === 'Linux') {
62-
return `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}.deb`
62+
return `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}-${type}.deb`
6363
}
6464
return '#'
6565
}
66+
6667
const allLinks = [
6768
{
6869
label: 'Windows 64-bit',
69-
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-x64-${version}.exe`,
70+
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-x64-${version}-obs.exe`,
7071
},
7172
{
7273
label: 'Windows 32-bit',
73-
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-ia32-${version}.exe`,
74+
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL-win-ia32-${version}-obs.exe`,
7475
},
7576
{
7677
label: 'Linux .deb',
77-
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}.deb`,
78+
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}-bible.deb`,
7879
},
7980
{
8081
label: 'Linux AppImage',
81-
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}.AppImage`,
82+
link: `https://github.com/hiscoder-com/level-desktop/releases/download/v${version}/LEVEL_${version}-bible.AppImage`,
8283
},
8384
]
8485
const isAvailableCurrentOs = availableOs.includes(os.os)
@@ -99,9 +100,17 @@ function Download({ t, onClose }) {
99100
</ol>
100101
<p>{t('Download.p2')}</p>
101102
{isAvailableCurrentOs ? (
102-
<Link href={getDownloadLink()} className="font-bold text-th-primary-100">
103-
{t('Download.link')}
104-
</Link>
103+
<>
104+
<Link href={getDownloadLink('obs')} className="font-bold text-th-primary-100">
105+
{t('Download.linkObs')}
106+
</Link>
107+
<Link
108+
href={getDownloadLink('bible')}
109+
className="font-bold text-th-primary-100"
110+
>
111+
{t('Download.linkBible')}
112+
</Link>
113+
</>
105114
) : (
106115
allLinks.map((download) => (
107116
<Link

pages/api/obs-images.js

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import { supabaseService } from 'utils/supabaseService'
2+
3+
export default async function handler(req, res) {
4+
const { method } = req
5+
6+
const handleError = (error, errorMessage) => {
7+
console.error(errorMessage, error)
8+
res.status(500).json({ error: 'Internal Server Error' })
9+
}
10+
11+
switch (method) {
12+
case 'GET':
13+
try {
14+
const { data: fileData, error: fileError } = supabaseService.storage
15+
.from('obs-images')
16+
.getPublicUrl('obs-images-360px.zip')
17+
18+
if (fileError) {
19+
console.error(`Error fetching URL for obs-images:`, fileError)
20+
return null
21+
}
22+
23+
return res.status(200).json({ data: fileData?.publicUrl })
24+
} catch (error) {
25+
return handleError(error, 'Server error:')
26+
}
27+
28+
default:
29+
res.setHeader('Allow', ['GET'])
30+
res.status(405).end(`Method ${method} Not Allowed`)
31+
}
32+
}

public/locales/en/start-page.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111
"li2": "Run the file and follow the installation prompts.",
1212
"li3": "Once installed, open the program to explore the test project and familiarize yourself with the platform.",
1313
"p2": "We hope you enjoy using LEVEL! Stay tuned for updates and future releases for other operating systems.",
14-
"link": "Download LEVEL Desktop"
14+
"linkObs": "Download LEVEL Desktop with OBS project",
15+
"linkBible": "Download LEVEL Desktop with Bible project"
1516
},
1617
"Iagree": "I agree",
1718
"Idecline": "I decline",
@@ -92,4 +93,4 @@
9293
"text": "And this gospel of the kingdom will be preached in the whole world for a testimony to all the nations, and then the end will come."
9394
},
9495
"YourMessageHasBeenSent": "Your message has been sent"
95-
}
96+
}

0 commit comments

Comments
 (0)