mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-02-24 23:48:13 -05:00
✨ Added media file support to the zip importer
refs https://github.com/TryGhost/Toolbox/issues/523 - When migrating or importing ZIP files into Ghost there's often a need to include more than just post content and images. - When media files are present in the imported zip file they are now copied across and processed along with the rest of import files: json, images, csvs, etc. - The importer also searches for use of the media files in the imported "posts" substituting the links with local ones - The media importer recognizes media files inside of "media" or "content/media" folders present in the zip. The supported media file extensions are same as for media upload widget: ".mp4", ".webm", ".ogv", ".mp3", ".wav", ".ogg", ".m4a" with following content-types: "video/mp4", "video/webm", "video/ogg", "audio/mpeg", "audio/vnd.wav", "audio/wave", "audio/wav", "audio/x-wav", "audio/ogg", "audio/mp4", "audio/x-m4a"
This commit is contained in:
parent
49553e5942
commit
2361669bb6
3 changed files with 47 additions and 15 deletions
|
@ -64,10 +64,15 @@ class ImportManager {
|
|||
type: 'images',
|
||||
store: imageStorage
|
||||
});
|
||||
const mediaImporter = new ContentFileImporter({
|
||||
type: 'media',
|
||||
store: mediaStorage
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {Importer[]} importers
|
||||
*/
|
||||
this.importers = [imageImporter, RevueImporter, DataImporter];
|
||||
this.importers = [imageImporter, mediaImporter, RevueImporter, DataImporter];
|
||||
|
||||
/**
|
||||
* @type {Handler[]}
|
||||
|
|
|
@ -15,14 +15,21 @@ replaceImage = function (markdown, image) {
|
|||
return markdown.replace(regex, image.newPath);
|
||||
};
|
||||
|
||||
preProcessPosts = function (data, image) {
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {Object[]} data.posts
|
||||
* @param {Object} contentFile
|
||||
* @param {String} contentFile.originalPath
|
||||
* @param {String} contentFile.newPath
|
||||
*/
|
||||
preProcessPosts = function (data, contentFile) {
|
||||
_.each(data.posts, function (post) {
|
||||
post.markdown = replaceImage(post.markdown, image);
|
||||
post.markdown = replaceImage(post.markdown, contentFile);
|
||||
if (post.html) {
|
||||
post.html = replaceImage(post.html, image);
|
||||
post.html = replaceImage(post.html, contentFile);
|
||||
}
|
||||
if (post.feature_image) {
|
||||
post.feature_image = replaceImage(post.feature_image, image);
|
||||
post.feature_image = replaceImage(post.feature_image, contentFile);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
@ -56,7 +63,7 @@ class ContentFileImporter {
|
|||
/**
|
||||
*
|
||||
* @param {Object} deps
|
||||
* @param {'images'} deps.type - importer type
|
||||
* @param {'images' | 'media'} deps.type - importer type
|
||||
* @param {import('ghost-storage-base')} deps.store
|
||||
*/
|
||||
constructor(deps) {
|
||||
|
@ -65,15 +72,30 @@ class ContentFileImporter {
|
|||
}
|
||||
|
||||
preProcess(importData) {
|
||||
if (importData.images && importData.data) {
|
||||
_.each(importData.images, function (image) {
|
||||
preProcessPosts(importData.data.data, image);
|
||||
preProcessTags(importData.data.data, image);
|
||||
preProcessUsers(importData.data.data, image);
|
||||
});
|
||||
if (this.type === 'images') {
|
||||
if (importData.images && importData.data){
|
||||
_.each(importData.images, function (image) {
|
||||
preProcessPosts(importData.data.data, image);
|
||||
preProcessTags(importData.data.data, image);
|
||||
preProcessUsers(importData.data.data, image);
|
||||
});
|
||||
}
|
||||
|
||||
importData.preProcessedByImage = true;
|
||||
}
|
||||
|
||||
// @NOTE: the type === 'media' check does not belong here and should be abstracted away
|
||||
// to make this importer more generic
|
||||
if (this.type === 'media') {
|
||||
if (importData.media && importData.data) {
|
||||
_.each(importData.media, function (file) {
|
||||
preProcessPosts(importData.data.data, file);
|
||||
});
|
||||
}
|
||||
|
||||
importData.preProcessedByMedia = true;
|
||||
}
|
||||
|
||||
importData.preProcessedByImage = true;
|
||||
return importData;
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ describe('Importer', function () {
|
|||
describe('ImportManager', function () {
|
||||
it('has the correct interface', function () {
|
||||
ImportManager.handlers.should.be.instanceof(Array).and.have.lengthOf(5);
|
||||
ImportManager.importers.should.be.instanceof(Array).and.have.lengthOf(3);
|
||||
ImportManager.importers.should.be.instanceof(Array).and.have.lengthOf(4);
|
||||
ImportManager.loadFile.should.be.instanceof(Function);
|
||||
ImportManager.preProcess.should.be.instanceof(Function);
|
||||
ImportManager.doImport.should.be.instanceof(Function);
|
||||
|
@ -391,7 +391,11 @@ describe('Importer', function () {
|
|||
describe('preProcess', function () {
|
||||
// preProcess can modify the data prior to importing
|
||||
it('calls the DataImporter preProcess method', function (done) {
|
||||
const input = {data: {}, images: []};
|
||||
const input = {
|
||||
data: {},
|
||||
images: [],
|
||||
media: []
|
||||
};
|
||||
|
||||
// pass a copy so that input doesn't get modified
|
||||
const inputCopy = _.cloneDeep(input);
|
||||
|
@ -412,6 +416,7 @@ describe('Importer', function () {
|
|||
output.should.not.equal(input);
|
||||
output.should.have.property('preProcessedByData', true);
|
||||
output.should.have.property('preProcessedByImage', true);
|
||||
output.should.have.property('preProcessedByMedia', true);
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
|
|
Loading…
Add table
Reference in a new issue