Skip to content
Merged
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
2 changes: 2 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ async function main() {
}
case "get-folders": {
const folders = feed.getFolders(FOLDERS);
report += folders.length + " Folders" + "\n";
folders.forEach((folder) => {
report += folder.report() + "\n";
});
Expand All @@ -114,6 +115,7 @@ async function main() {
platforms: PLATFORMS,
status: STATUS,
});
report += allposts.length + " Posts" + "\n";
allposts.forEach((post) => {
report += post.report();
});
Expand Down
4 changes: 2 additions & 2 deletions src/models/Feed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export default class Feed {
}

/**
* Get one post
* Get one (prepared) post
* @param path - path to a single folder
* @param platformId - the platform for the post
* @returns the given post, or undefined if not prepared
Expand All @@ -200,7 +200,7 @@ export default class Feed {
}

/**
* Get multiple posts
* Get multiple (prepared) posts
* @param filters - object to filter posts by
* @param filters.folders - paths to folders to filter on
* @param filters.platforms - slugs to platforms to filter on
Expand Down
28 changes: 19 additions & 9 deletions src/models/Platform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ export default class Platform {
active: boolean = false;
id: PlatformId = PlatformId.UNKNOWN;
defaultBody: string = "Fairpost feed";
postFile: string = "post.json";

/**
* Return a small report for this feed
Expand All @@ -31,12 +32,22 @@ export default class Platform {
}

/**
* getPostFileName
* @returns the intended name for a post of this
* platform to be saved in this folder.
* getAssetsFolderName
* @returns the relative path to a folder used
* to store assets for a post of this platform
*/
getPostFileName(): string {
return "_" + this.id + ".json";
assetsFolder(): string {
return "_" + this.id;
}

/**
* getPostFilePath
* @param folder the folder for the new or existing post
* @returns the full path to the post file used
* to store data for a post of this platform
*/
getPostFilePath(folder: Folder): string {
return folder.path + "/" + this.assetsFolder() + "/" + this.postFile;
}

/**
Expand All @@ -48,10 +59,9 @@ export default class Platform {
getPost(folder: Folder): Post | undefined {
Logger.trace("Platform", "getPost");

if (fs.existsSync(folder.path + "/" + this.getPostFileName())) {
const data = JSON.parse(
fs.readFileSync(folder.path + "/" + this.getPostFileName(), "utf8"),
);
const postFilePath = this.getPostFilePath(folder);
if (fs.existsSync(postFilePath)) {
const data = JSON.parse(fs.readFileSync(postFilePath, "utf8"));
if (data) {
return new Post(folder, this, data);
}
Expand Down
29 changes: 28 additions & 1 deletion src/models/Post.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ export default class Post {
this.scheduled = this.scheduled ? new Date(this.scheduled) : undefined;
this.published = this.published ? new Date(this.published) : undefined;
}
const assetsPath = this.getFullPath(platform.assetsFolder());
if (!fs.existsSync(assetsPath)) {
fs.mkdirSync(assetsPath, { recursive: true });
}
}

/**
Expand Down Expand Up @@ -70,7 +74,7 @@ export default class Post {
delete data.folder;
delete data.platform;
fs.writeFileSync(
this.folder.path + "/" + this.platform.getPostFileName(),
this.platform.getPostFilePath(this.folder),
JSON.stringify(data, null, "\t"),
);
}
Expand All @@ -88,6 +92,29 @@ export default class Post {
this.status = PostStatus.SCHEDULED;
this.save();
}

/**
* @param filename relative path in this post.folder
* @returns the full path to that file
*/
getFullPath(filename: string): string {
return this.folder.path + "/" + filename;
}

/**
* Replace a file in the post with an alternative
* @param src relative path in this post.folder
* @param dst relative path in this post.folder
*/
useAlternativeFile(src: string, dst: string) {
for (const type in this.files) {
if (this.files[type].includes(src)) {
// be simple for now
this.files[type].push(dst);
this.files[type] = this.files[type].filter((file) => file !== src);
}
}
}
}

export interface PostResult {
Expand Down
15 changes: 7 additions & 8 deletions src/platforms/Ayrshare/AsFacebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,17 @@ export default class AsFacebook extends Ayrshare {
const post = await super.preparePost(folder);
if (post) {
// facebook : max 10mb images
for (const image of post.files.image) {
const size =
fs.statSync(post.folder.path + "/" + image).size / (1024 * 1024);
for (const src of post.files.image) {
const dst = this.assetsFolder() + "/facebook-" + src;
const size = fs.statSync(post.getFullPath(src)).size / (1024 * 1024);
if (size >= 10) {
console.log("Resizing " + image + " for facebook ..");
await sharp(post.folder.path + "/" + image)
console.log("Resizing " + src + " for facebook ..");
await sharp(post.getFullPath(src))
.resize({
width: 1200,
})
.toFile(post.folder.path + "/_facebook-" + image);
post.files.image.push("_facebook-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}
post.save();
Expand Down
36 changes: 22 additions & 14 deletions src/platforms/Ayrshare/AsInstagram.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import * as path from "path";
import * as sharp from "sharp";

import Ayrshare from "../Ayrshare";
Expand All @@ -18,30 +19,37 @@ export default class AsInstagram extends Ayrshare {

async preparePost(folder: Folder): Promise<Post | undefined> {
const post = await super.preparePost(folder);
if (post) {
if (post && post.files) {
// instagram: 1 video for reel
if (post.files.video.length) {
Logger.trace("Removing images for instagram reel..");
post.files.image = [];
if (post.files.video.length > 1) {
Logger.trace("Using first video for instagram reel..");
post.files.video = [post.files.video[0]];
if (post.files.video.length > 10) {
Logger.trace("Removing > 10 videos for instagram caroussel..");
post.files.video.length = 10;
}
const remaining = 10 - post.files.video.length;
if (post.files.image.length > remaining) {
Logger.trace("Removing some images for instagram caroussel..");
post.files.image.length = remaining;
}
}
// instagram : scale images
for (const image of post.files.image) {
const metadata = await sharp(post.folder.path + "/" + image).metadata();

// instagram : scale images, jpeg only
for (const src of post.files.image) {
const metadata = await sharp(post.getFullPath(src)).metadata();
if (metadata.width > 1440) {
Logger.trace("Resizing " + image + " for instagram ..");
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for instagram ..");
const extension = src.split(".")?.pop();
const basename = path.basename(src, extension ? "." + extension : "");
const dst = this.assetsFolder() + "/instagram-" + basename + ".JPEG";
await sharp(post.getFullPath(src))
.resize({
width: 1440,
})
.toFile(post.folder.path + "/_instagram-" + image);
post.files.image.push("_instagram-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}

// instagram: require media
if (post.files.image.length + post.files.video.length === 0) {
post.valid = false;
Expand Down
15 changes: 7 additions & 8 deletions src/platforms/Ayrshare/AsLinkedIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,17 @@ export default class AsLinkedIn extends Ayrshare {
);
}
// linkedin: max 5mb images
for (const image of post.files.image) {
const size =
fs.statSync(post.folder.path + "/" + image).size / (1024 * 1024);
for (const src of post.files.image) {
const dst = this.assetsFolder() + "/linkedin-" + src;
const size = fs.statSync(post.getFullPath(src)).size / (1024 * 1024);
if (size >= 5) {
Logger.trace("Resizing " + image + " for linkedin ..");
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for linkedin ..");
await sharp(post.getFullPath(src))
.resize({
width: 1200,
})
.toFile(post.folder.path + "/_linkedin-" + image);
post.files.image.push("_linkedin-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}
post.save();
Expand Down
15 changes: 7 additions & 8 deletions src/platforms/Ayrshare/AsTwitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,18 +27,17 @@ export default class AsTwitter extends Ayrshare {
post.files.image.length = 4;
}
// twitter: max 5mb images
for (const image of post.files.image) {
const size =
fs.statSync(post.folder.path + "/" + image).size / (1024 * 1024);
for (const src of post.files.image) {
const dst = this.assetsFolder() + "/twitter-" + src;
const size = fs.statSync(post.getFullPath(src)).size / (1024 * 1024);
if (size >= 5) {
Logger.trace("Resizing " + image + " for twitter ..");
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for twitter ..");
await sharp(post.getFullPath(src))
.resize({
width: 1200,
})
.toFile(post.folder.path + "/_twitter-" + image);
post.files.image.push("_twitter-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}
post.save();
Expand Down
15 changes: 7 additions & 8 deletions src/platforms/Facebook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,18 +47,17 @@ export default class Facebook extends Platform {
post.files.image = [];
}
// facebook : max 4mb images
for (const image of post.files.image) {
const size =
fs.statSync(post.folder.path + "/" + image).size / (1024 * 1024);
for (const src of post.files.image) {
const dst = this.assetsFolder() + "/facebook-" + src;
const size = fs.statSync(post.getFullPath(src)).size / (1024 * 1024);
if (size >= 4) {
Logger.trace("Resizing " + image + " for facebook ..");
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for facebook ..");
await sharp(post.getFullPath(src))
.resize({
width: 1200,
})
.toFile(post.folder.path + "/_facebook-" + image);
post.files.image.push("_facebook-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}
post.save();
Expand Down
22 changes: 9 additions & 13 deletions src/platforms/Instagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,23 +55,19 @@ export default class Instagram extends Platform {
}

// instagram : scale images, jpeg only
for (const image of post.files.image) {
const metadata = await sharp(post.folder.path + "/" + image).metadata();
for (const src of post.files.image) {
const metadata = await sharp(post.getFullPath(src)).metadata();
if (metadata.width > 1440) {
Logger.trace("Resizing " + image + " for instagram ..");
const extension = image.split(".")?.pop();
const basename = path.basename(
image,
extension ? "." + extension : "",
);
const outfile = "_instagram-" + basename + ".JPEG";
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for instagram ..");
const extension = src.split(".")?.pop();
const basename = path.basename(src, extension ? "." + extension : "");
const dst = this.assetsFolder() + "/instagram-" + basename + ".JPEG";
await sharp(post.getFullPath(src))
.resize({
width: 1440,
})
.toFile(post.folder.path + "/" + outfile);
post.files.image.push(outfile);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}

Expand Down
15 changes: 7 additions & 8 deletions src/platforms/LinkedIn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,17 @@ export default class LinkedIn extends Platform {
}

// linkedin: max 5mb images
for (const image of post.files.image) {
const size =
fs.statSync(post.folder.path + "/" + image).size / (1024 * 1024);
for (const src of post.files.image) {
const dst = this.assetsFolder() + "/linkedin-" + src;
const size = fs.statSync(post.getFullPath(src)).size / (1024 * 1024);
if (size >= 5) {
Logger.trace("Resizing " + image + " for linkedin ..");
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for linkedin ..");
await sharp(post.getFullPath(src))
.resize({
width: 1200,
})
.toFile(post.folder.path + "/_linkedin-" + image);
post.files.image.push("_linkedin-" + image);
post.files.image = post.files.image.filter((file) => file !== image);
.toFile(post.getFullPath(dst));
post.useAlternativeFile(src, dst);
}
}
post.save();
Expand Down
23 changes: 10 additions & 13 deletions src/platforms/Reddit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,27 +48,24 @@ export default class Reddit extends Platform {
if (post) {
// reddit: max 1 image or video
// TODO: extract video thumbnail
if (false && post.files.video.length >= 1) { // eslint-disable-line
if (post.files.video.length >= 1) { // eslint-disable-line
post.files.video.length = 1;
post.files.image = [];
} else if (post.files.image.length > 1) {
// <MaxSizeAllowed>20971520</MaxSizeAllowed>
const image = post.files.image[0];
const metadata = await sharp(post.folder.path + "/" + image).metadata();
const src = post.files.image[0];
const metadata = await sharp(post.getFullPath(src)).metadata();
if (metadata.width > 3000) {
Logger.trace("Resizing " + image + " for reddit ..");
const extension = image.split(".")?.pop();
const basename = path.basename(
image,
extension ? "." + extension : "",
);
const outfile = "_reddit-" + basename + ".jpg";
await sharp(post.folder.path + "/" + image)
Logger.trace("Resizing " + src + " for reddit ..");
const extension = src.split(".")?.pop();
const basename = path.basename(src, extension ? "." + extension : "");
const dst = this.assetsFolder() + "/reddit-" + basename + ".jpg";
await sharp(post.getFullPath(src))
.resize({
width: 3000,
})
.toFile(post.folder.path + "/" + outfile);
post.files.image = [outfile];
.toFile(post.getFullPath(dst));
post.files.image = [dst];
}
}
post.save();
Expand Down
Loading