Skip to content

Commit

Permalink
Burrito translation multimedia and notes (#373)
Browse files Browse the repository at this point in the history
* changed place of the 'nprogress' by few px

* trying a configuration to increase 'maxConcurrentTasks'

* removed @mui/icons-react from deps and let it in devDeps

* added the full feature with images clickable

* change message from 'No resources image for this book' to 'No resources image for this verse'

* change message from 'No resources image for this verse' to 'No resources image for this Chapter/Verse'

* now the tn are forced to be downloaded once before being displayed as a resource, and fixe a css problem

* changed a typo

* now you can load even videos out of a burrito

* implemented caching for videos

* fixed a minor bug with filepath system

* few bugfix, regarding juxtalinear editor and renaming the translationHelpImageCard to translationHelpMultimediaCard

* added missing file

* removed useless console.log

* lint fixes

* securely removed the extension files at the end of a multimedia title

* removed commented code

* mini optimisation

---------

Co-authored-by: danielc-n <[email protected]>
  • Loading branch information
DanielC-N and danielc-n authored Oct 24, 2024
1 parent edd9945 commit 958871b
Show file tree
Hide file tree
Showing 19 changed files with 1,377 additions and 525 deletions.
33 changes: 33 additions & 0 deletions main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,39 @@ function isDev() {
return process.argv[2] == '--dev';
}

const CACHE_DIR = path.join(app.getPath('userData'), 'video-cache');

if (!fs.existsSync(CACHE_DIR)) {
fs.mkdirSync(CACHE_DIR);
}

// Handle requests to check if a video is cached
ipcMain.handle('is-video-cached', (event, videoUrl) => {
const videoFileName = path.basename(videoUrl);
const localVideoPath = path.join(CACHE_DIR, videoFileName);
return fs.existsSync(localVideoPath) ? localVideoPath : null;
});

// Handle requests to download and cache the video
ipcMain.handle('download-and-cache-video', async (event, videoUrl) => {
const videoFileName = path.basename(videoUrl);
const localVideoPath = path.join(CACHE_DIR, videoFileName);

const net = require('electron').net;
const request = net.request(videoUrl);

return new Promise((resolve, reject) => {
const fileStream = fs.createWriteStream(localVideoPath);
request.on('response', (response) => {
response.pipe(fileStream);
fileStream.on('finish', () => resolve(localVideoPath));
});

request.on('error', reject);
request.end();
});
});

async function setPermissions(chromePath) {
try {
fs.chmodSync(chromePath, '755');
Expand Down
2 changes: 2 additions & 0 deletions renderer/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const environment = {
GITEA_SERVER: 'https://git.door43.org',
GITEA_TOKEN: 'Gitea AG Testing',
GITEA_API_ENDPOINT: 'https://git.door43.org/api/v1',
GITHUB_SERVER: 'https://github.com',
GITHUB_API_ENDPOINT: 'https://api.github.com',
uuidToken: '6223f833-3e59-429c-bec9-16910442b599',
SYNC_BACKUP_COUNT: 5,
AG_MINIMUM_BURRITO_VERSION: '0.3.0',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default function SelectBook({
function bookSelect(e, bookId) {
e.preventDefault();
onChangeBook(bookId, selectedBooks[0]);
setBook(bookId);
setBook && setBook(bookId);
if (multiSelectBook === false) { selectBook(); }
}

Expand Down
67 changes: 66 additions & 1 deletion renderer/src/components/EditorPage/Reference/TranslationHelps.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
import React, { useContext } from 'react';
import React, { useContext, useState, useEffect } from 'react';
import * as localforage from 'localforage';
import PropTypes from 'prop-types';
import { useTranslation } from 'react-i18next';
import { ReferenceContext } from '@/components/context/ReferenceContext';
import { debug } from '../../../logger';
import TranslationHelpsCard from './TranslationHelpsCard';
import TranslationHelpsMultimediaCard from './TranslationHelpsMultimediaCard';
import ObsTnCard from './OBS/ObsTn';
import ObsTwlCard from './OBS/ObsTwlCard';
import packageInfo from '../../../../../package.json';

const TranslationHelps = ({
selectedResource, languageId, refName, bookId, chapter, verse, owner, story, offlineResource, font, fontSize,
Expand All @@ -17,16 +21,58 @@ const TranslationHelps = ({
} = useContext(ReferenceContext);
const { t } = useTranslation();

/**
* Function to search a directory for a file containing a specific name part.
* @param {string} directoryPath - The path of the directory to search in.
* @param {string} partialName - The partial name to search for in the file names.
* @returns {string|null} - The full name of the matched file, or null if not found.
*/
const findFileByPartialName = (fsInstance, directoryPath, partialName) => fsInstance.readdirSync(directoryPath).find((file) => file.includes(partialName)) || null;

const translationQuestionsPath = `${(chapter < 10) ? (`0${ chapter}`)
: chapter}/${(verse < 10) ? (`0${ verse}`) : verse}.md`;

const filePathTa = `${taNavigationPath?.path}/01.md`;

const [resourceLinkPath, setResourceLinkPath] = useState('');
const [imagesPath, setImagesPath] = useState('');

useEffect(() => {
async function getLinkedFolderPath() {
const fs = window.require('fs');
const path = window.require('path');
try {
const newpath = localStorage.getItem('userPath');
const userProfile = await localforage.getItem('userProfile');
const resourceDirPath = path.join(newpath, packageInfo.name, 'users', userProfile?.username, 'resources');
const pathToIngredients = path.resolve(resourceDirPath, offlineResource.data.projectDir, 'ingredients');
if (pathToIngredients) {
const pathRelationFile = path.resolve(pathToIngredients, 'relation.txt');
if (fs.existsSync(pathRelationFile)) {
setImagesPath(pathToIngredients);
const relationFileContent = fs.readFileSync(pathRelationFile, 'utf8');
const fileName = findFileByPartialName(fs, path.resolve(resourceDirPath), relationFileContent.trim());
setResourceLinkPath(path.resolve(resourceDirPath, fileName, 'ingredients'));
} else {
setImagesPath('');
setResourceLinkPath(pathToIngredients);
debug('TranslationHelps.js', `pathRelationFile : ${pathRelationFile} - Not found!`);
}
}
} catch (e) {
debug('TranslationHelps.js', `Error : ${e}`);
}
}

getLinkedFolderPath();
}, [selectedResource, offlineResource]);

return (
<>
{(() => {
switch (selectedResource) {
case 'tn':
case 'x-bcvnotes':
return (
<TranslationHelpsCard
title={t('label-resource-tn')}
Expand All @@ -43,6 +89,25 @@ const TranslationHelps = ({
fontSize={fontSize}
/>
);
case 'tir':
return (
<TranslationHelpsMultimediaCard
title={t('label-resource-tir')}
verse={verse}
chapter={chapter}
projectId={bookId.toUpperCase() || 'mat'.toUpperCase()}
branch={branch}
languageId={languageId}
resourceId="tir"
owner={owner}
server="https://git.door43.org"
offlineResource={offlineResource}
font={font}
fontSize={fontSize}
folderPath={resourceLinkPath}
linkedFolderPath={imagesPath}
/>
);
// case 'twl':
// return (
// <TranslationHelpsCard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,29 @@ export default function TranslationHelpsCard({
const [currentChapterVerse, setCurrentChapterVerse] = useState({ verse, chapter });

// eslint-disable-next-line prefer-const
let { items, markdown, isLoading } = useContent({
verse: currentChapterVerse.verse,
chapter: currentChapterVerse.chapter,
projectId,
branch,
languageId,
resourceId,
filePath,
owner,
server,
readyToFetch: true,
});
let items = [];
let markdown = '';
let isLoading;
try {
const tmpRes = useContent({
verse: currentChapterVerse.verse,
chapter: currentChapterVerse.chapter,
projectId,
branch,
languageId,
resourceId,
filePath,
owner,
// server:"https://api.github.com",
server,
readyToFetch: true,
});
items = tmpRes.items;
markdown = tmpRes.markdown;
isLoading = tmpRes.isLoading;
} catch (e) {
logger.debug('TranslationHelpsCard.js', 'Error setting up in useContent');
}

useEffect(() => {
if (currentTnTab === 1) {
Expand All @@ -73,26 +84,56 @@ export default function TranslationHelpsCard({
try {
setOfflineMarkdown('');
setOfflineItems('');
let isBurrito = false;
localForage.getItem('userProfile').then(async (user) => {
logger.debug('TranslationHelpsCard.js', `reading offline helps ${offlineResource.data?.projectDir}`);
const fs = window.require('fs');
const path = require('path');
const newpath = localStorage.getItem('userPath');
const currentUser = user?.username;
const folder = path.join(newpath, packageInfo.name, 'users', `${currentUser}`, 'resources');
const projectName = `${offlineResource?.data?.value?.meta?.name}_${offlineResource?.data?.value?.meta?.owner}_${offlineResource?.data?.value?.meta?.release?.tag_name}`;
let projectName = `${offlineResource?.data?.value?.meta?.name}_${offlineResource?.data?.value?.meta?.owner}_${offlineResource?.data?.value?.meta?.release?.tag_name}`;
if (!offlineResource?.data?.value?.meta?.name) {
isBurrito = true;
projectName = offlineResource?.data?.projectDir;
}
// projectName = `${offlineResource?.data?.value?.meta?.name}_${offlineResource?.data?.value?.meta?.owner}_${offlineResource?.data?.value?.meta?.release?.tag_name}`;
// switch resources
switch (resourceId) {
case 'tn':
case 'x-bcvnotes':
// console.log("yep", folder, 'and projectName ==', projectName);
if (fs.existsSync(path.join(folder, projectName))) {
// eslint-disable-next-line array-callback-return
const currentFile = offlineResource?.data?.value?.projects.filter((item) => {
if (item?.identifier.toLowerCase() === projectId.toLowerCase()) {
return item;
let currentFile;
if (isBurrito) {
const asArray = Object.entries(offlineResource?.data?.value?.ingredients);
// currentFile = asArray.filter(([key, value]) => {
// if (key.toLocaleLowerCase().indexOf(projectId.toLowerCase()) !== -1) {
// console.log("key ==", key);
// console.log("value ==", value);
// return value;
// }
// return [];
// })[0];
// eslint-disable-next-line
for (const [key, value] of asArray) {
if (key.toLocaleLowerCase().indexOf(projectId.toLowerCase()) !== -1) {
currentFile = key;
break;
}
}
});
} else {
currentFile = offlineResource?.data?.value?.projects.filter((item) => {
if (item?.identifier.toLowerCase() === projectId.toLowerCase()) {
return item;
}
return null;
});
}
if (currentFile?.length > 0) {
const filecontent = await fs.readFileSync(path.join(folder, projectName, currentFile[0].path), 'utf8');
// const filecontent = await fs.readFileSync(path.join(folder, projectName, currentFile[0].path), 'utf8');
const filecontent = await fs.readFileSync(path.join(folder, projectName, isBurrito ? currentFile : currentFile[0].path), 'utf8');
// convert tsv to json
const headerArr = filecontent.split('\n')[0].split('\t');
let noteName;
Expand All @@ -111,21 +152,21 @@ export default function TranslationHelpsCard({
}

const json = filecontent.split('\n')
.map((file) => {
.map((line) => {
if (bvcType) {
const [Book, Chapter, Verse, ID, SupportReference, OrigQuote, Occurrence, GLQuote, OccurrenceNote] = file.split('\t');
const [Book, Chapter, Verse, ID, SupportReference, OrigQuote, Occurrence, GLQuote, OccurrenceNote] = line.split('\t');
return {
Book, Chapter, Verse, ID, SupportReference, OrigQuote, Occurrence, GLQuote, OccurrenceNote,
};
}
const Book = projectId;
const [ref, ID] = file.split('\t');
const [ref, ID] = line.split('\t');
const Chapter = ref.split(':')[0];
const Verse = ref.split(':')[1];
return {
Book, Chapter, Verse, ID, [noteName]: file.split('\t')[indexOfNote],
Book, Chapter, Verse, ID, [noteName]: line.split('\t')[indexOfNote],
};
}).filter((data) => data.Chapter === currentChapterVerse.chapter && data.Verse === currentChapterVerse.verse);
}).filter((data) => data.Chapter === `${currentChapterVerse.chapter }` && data.Verse === `${currentChapterVerse.verse }`);
setOfflineItemsDisable(false);
setOfflineItems(json);
}
Expand Down Expand Up @@ -200,7 +241,7 @@ export default function TranslationHelpsCard({
setOfflineItemsDisable(true);
setOfflineMarkdown(filecontent);
} else {
setOfflineMarkdown({ error: true, data: 'No Content Avaialble' });
setOfflineMarkdown({ error: true, data: 'No Content Available' });
}
}
});
Expand Down Expand Up @@ -247,7 +288,7 @@ export default function TranslationHelpsCard({
items = !offlineItemsDisable && offlineResource?.offline ? offlineItems : items;
markdown = offlineResource?.offline ? offlineMarkdown : markdown;

if (resourceId === 'tn' && items) {
if ((resourceId === 'tn' || resourceId === 'x-bcvnotes') && items) {
if (items[0]?.Note) {
items[0].Note = (items[0].Note).replace(/(<br>|\\n)/gm, '\n');
}
Expand All @@ -258,7 +299,7 @@ export default function TranslationHelpsCard({

return (
<>
{resourceId === 'tn' && (<TabSelector currentTab={currentTnTab} setCurrentTab={setCurrentTnTab} tabData={tnTabHeads} />)}
{(resourceId === 'tn' || resourceId === 'x-bcvnotes') && (<TabSelector currentTab={currentTnTab} setCurrentTab={setCurrentTnTab} tabData={tnTabHeads} />)}
{(markdown || items) ? (
<ReferenceCard
resourceId={resourceId}
Expand Down
Loading

0 comments on commit 958871b

Please sign in to comment.