Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download images alongside site files #16

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 84 additions & 5 deletions src/lib/views/modal/Deploy.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { get } from 'svelte/store'
import { createUniqueID } from '$lib/utilities'
import pages from '$lib/stores/data/pages'
import symbols from '$lib/stores/data/symbols'
// import beautify from 'js-beautify' // remove for now to reduce bundle size, dynamically import later if wanted
Expand Down Expand Up @@ -28,11 +29,13 @@ export async function push_site(repo_name, create_new = false) {
return await deploy({ files, site_id: get(site).id, repo_name }, create_new)
}

export async function build_site_bundle({ pages, symbols }) {
export async function build_site_bundle({ pages, symbols }, include_assets = false) {
let site_bundle

let all_sections = []
let all_pages = []
const all_sections = []
const all_pages = []
const image_files = []

try {
const page_files = await Promise.all(
pages.map((page) => {
Expand Down Expand Up @@ -84,6 +87,17 @@ export async function build_site_bundle({ pages, symbols }) {
order: ['index', { ascending: true }]
})

// Download images & replace urls in sections
if (include_assets && has_nested_property(sections, 'alt')) {
await Promise.all(
sections.map(async (section, i) => {
const response = await swap_in_local_asset_urls(section.content)
image_files.push(...response.image_files) // store image blobs for later download
sections[i]['content'] = response.content // replace image urls in content with relative urls
})
)
}

const { html } = await buildStaticPage({
page,
page_sections: sections,
Expand Down Expand Up @@ -128,8 +142,8 @@ export async function build_site_bundle({ pages, symbols }) {
full_url = `${language}/${full_url}`
} else {
// only add en sections and pages to primo.json
all_sections = [...all_sections, ...sections]
all_pages = [...all_pages, page]
all_sections.push(...sections)
all_pages.push(page)
}

const page_tree = [
Expand Down Expand Up @@ -184,6 +198,7 @@ export async function build_site_bundle({ pages, symbols }) {
})

return [
...image_files,
..._.flattenDeep(pages),
{
path: `primo.json`,
Expand Down Expand Up @@ -214,3 +229,67 @@ export async function build_site_bundle({ pages, symbols }) {
]
}
}

/**
* @param {import('$lib').Content}
*/
async function swap_in_local_asset_urls(content) {
const files_to_fetch = []

const updated_content = _.mapValues(content, (lang_value) =>
_.mapValues(lang_value, (field_value) => {
if (typeof field_value === 'object' && field_value.hasOwnProperty('alt')) {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should check that field_value.url is not empty, i was getting errors when downloading the site

const urlObject = new URL(field_value.url)
const pathname = urlObject.pathname
const extension = pathname.slice(pathname.lastIndexOf('.'))
const filename =
field_value.alt.replace(/[\/:*?"<>|\s]/g, '_') + `---${createUniqueID()}` + extension

files_to_fetch.push({
url: field_value.url,
filename
})
return {
...field_value,
url: `./images/${filename}`
}
} else {
return field_value
}
})
)

// Download images
const image_files = []
await Promise.all(
files_to_fetch.map(async ({ url, filename }) => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be in a try catch since fetch can try to download forbidden assets, i have stumbled with this because i have some content with bad remote urls that can not be downloaded because of cors

const response = await fetch(url)
const blob = await response.blob()
console.log({ blob })

image_files.push({
path: `./images/${filename}`,
blob
})
})
)

return {
content: updated_content,
image_files
}
}

function has_nested_property(obj, key) {
if (obj.hasOwnProperty(key)) {
return true
}
for (let i in obj) {
if (typeof obj[i] === 'object') {
if (has_nested_property(obj[i], key)) {
return true
}
}
}
return false
}
10 changes: 7 additions & 3 deletions src/lib/views/modal/Deploy.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@

async function download_site() {
loading = true
const files = await build_site_bundle({ pages: $pages, symbols: $symbols })
const files = await build_site_bundle({ pages: $pages, symbols: $symbols }, true)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean it will always download the assets? A checkbox next to the download button would allow both options, with or without images.

if (!files) {
loading = false
return
Expand All @@ -69,8 +69,12 @@

async function create_site_zip(files) {
const zip = new JSZip()
files.forEach(({ path, content }) => {
zip.file(path, content)
files.forEach(({ path, content, blob }) => {
if (blob) {
zip.file(path, blob, { binary: true })
} else {
zip.file(path, content)
}
})
return await zip.generateAsync({ type: 'blob' })
}
Expand Down