@@ -15,7 +15,7 @@ import ButtonLoading from 'components/ButtonLoading'
1515import CheckBox from 'components/CheckBox'
1616import ListBox from 'components/ListBox'
1717
18- import { newTestamentList , usfmFileNames } from 'utils/config'
18+ import { newTestamentList , obsStoryVerses , usfmFileNames } from 'utils/config'
1919import {
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' )
0 commit comments