Skip to content

Commit

Permalink
Add support for video uploads. (#268)
Browse files Browse the repository at this point in the history
* Add support for video uploads

* Remove unnecessary console logs.

* Update to a signed apk in sample.

* add example of translations on app listing.

* Add better samples.

* Add better example of urls.

* Reduce video requirements to 720p
  • Loading branch information
ankur2136 authored May 3, 2024
1 parent 81d22fe commit 203bb06
Show file tree
Hide file tree
Showing 23 changed files with 118 additions and 35 deletions.
36 changes: 21 additions & 15 deletions example/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,50 @@ publisher:
email: [email protected]
media:
- purpose: icon
uri: ./media/publisher_icon.jpeg
uri: ./media/publisher_icon.png
app:
name: Cute Kittens
address: ''
android_package: com.solanamobile.cutekittens
urls:
license_url: https://cdn.org/license.html
copyright_url: https://cdn.org/copyright.html
privacy_policy_url: https://cdn.org/privacy.html
license_url: https://solanamobile.com/dapp-store-tos
copyright_url: https://solanamobile.com/dapp-store-tos
privacy_policy_url: https://solanamobile.com/privacy-policy
website: https://solanamobile.com
media:
- purpose: icon
uri: ./media/app_icon.jpeg
uri: ./media/app_icon.png
release:
address: ''
media:
- purpose: icon
uri: ./media/release_icon.png
- purpose: screenshot
uri: ./media/app_screenshot.png
uri: ./media/screenshot_1.png
- purpose: video
uri: ./media/demo.mp4
- purpose: screenshot
uri: ./media/app_screenshot1.png
uri: ./media/screenshot_2.png
- purpose: screenshot
uri: ./media/app_screenshot2.png
uri: ./media/screenshot_3.png
- purpose: screenshot
uri: ./media/app_screenshot3.png
- purpose: screenshot
uri: ./media/app_screenshot4.png
uri: ./media/screenshot_4.png
files:
- purpose: install
uri: ./files/app-debug.apk
uri: ./files/app-release.apk
catalog:
en-US:
name: This is a single release
short_description: A short description
name: Cute Kitten
short_description: Stories about cat
long_description: Some wonderful release notes, in long-form
new_in_version: Something new in this version
saga_features: Some information about saga specific features
fr-Fr:
name: App Name (in French)
short_description: App description (in French)
long_description: Some wonderful release notes, in long-form (in French)
new_in_version: Something new in this version (in French)
saga_features: Some information about saga specific features (in French)
solana_mobile_dapp_publisher_portal:
google_store_package: com.company.dapp.otherpkg
google_store_package: com.solanamobile.cutekitten.gps
testing_instructions: Here are some steps informing Solana Mobile of how to test this dapp. You can specify multiple lines of instructions. For example, if a login is needed, you would add those details here.
Binary file removed example/files/app-debug.apk
Binary file not shown.
Binary file added example/files/app-release.apk
Binary file not shown.
Binary file removed example/media/app_icon.jpeg
Binary file not shown.
Binary file added example/media/app_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed example/media/app_screenshot1.png
Binary file not shown.
Binary file removed example/media/app_screenshot2.png
Binary file not shown.
Binary file removed example/media/app_screenshot3.png
Binary file not shown.
Binary file removed example/media/app_screenshot4.png
Binary file not shown.
Binary file added example/media/demo.mp4
Binary file not shown.
Binary file removed example/media/publisher_icon.jpeg
Binary file not shown.
Binary file added example/media/publisher_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified example/media/release_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/media/screenshot_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/media/screenshot_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/media/screenshot_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added example/media/screenshot_4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 2 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
},
"devDependencies": {
"@metaplex-foundation/js": "0.20.0",
"@jest/globals": "^29.5.0",
"@jest/types": "^29.5.0",
"@metaplex-foundation/js": "0.20.0",
"@swc/jest": "^0.2.26",
"@types/commander": "^2.12.2",
"@types/debug": "^4.1.7",
Expand Down Expand Up @@ -64,6 +64,7 @@
"dotenv": "^16.0.3",
"esm": "^3.2.25",
"generate-schema": "^2.6.0",
"get-video-dimensions": "^1.0.0",
"image-size": "^1.0.2",
"js-yaml": "^4.1.0",
"semver": "^7.3.8",
Expand Down
3 changes: 0 additions & 3 deletions packages/cli/src/commands/ValidateCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ export const validateCommand = async ({

try {
validatePublisher(publisherJson);
console.info(`Publisher JSON valid!`);
} catch (e) {
const errorMsg = (e as Error | null)?.message ?? "";
showMessage(
Expand All @@ -55,7 +54,6 @@ export const validateCommand = async ({

try {
validateApp(appJson);
console.info(`App JSON valid!`);
} catch (e) {
const errorMsg = (e as Error | null)?.message ?? "";
showMessage(
Expand Down Expand Up @@ -86,7 +84,6 @@ export const validateCommand = async ({

try {
validateRelease(JSON.parse(objStringified));
console.info(`Release JSON valid!`);
} catch (e) {
const errorMsg = (e as Error | null)?.message ?? "";
showMessage(
Expand Down
61 changes: 54 additions & 7 deletions packages/cli/src/config/PublishDetails.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Constants, showMessage } from "../CliUtils.js";
import util from "util";
import { imageSize } from "image-size";
import { exec } from "child_process";
import getVideoDimensions from "get-video-dimensions";

const runImgSize = util.promisify(imageSize);
const runExec = util.promisify(exec);
Expand Down Expand Up @@ -125,19 +126,45 @@ export const loadPublishDetailsWithChecks = async (
}

config.release.media.forEach((item: PublishDetails["release"]["media"][0]) => {
const imagePath = path.join(process.cwd(), item.uri);
if (!fs.existsSync(imagePath) || !checkImageExtension(imagePath)) {
throw new Error(`Invalid media path or file type: ${item.uri}. Please ensure the file is a jpeg, png, or webp file.`);
const mediaPath = path.join(process.cwd(), item.uri);
if (!fs.existsSync(mediaPath)) {
throw new Error(`File doesnt exist: ${item.uri}.`)
}

if (item.purpose == "screenshot" && !checkImageExtension(mediaPath)) {
throw new Error(`Please ensure the file ${item.uri} is a jpeg, png, or webp file.`)
}

if (item.purpose == "video" && !checkVideoExtension(mediaPath)) {
throw new Error(`Please ensure the file ${item.uri} is a mp4.`)
}
}
);

const previewMediaFiles = config.release.media?.filter(
(asset: any) => asset.purpose === "screenshot" || asset.purpose === "video"
const screenshots = config.release.media?.filter(
(asset: any) => asset.purpose === "screenshot"
)

for (const item of screenshots) {
const mediaPath = path.join(process.cwd(), item.uri);
if (await checkScreenshotSize(mediaPath)) {
throw new Error(`Screenshot ${mediaPath} must be at least 1080px in width and height.`);
}
}

const videos = config.release.media?.filter(
(asset: any) => asset.purpose === "video"
)

if (previewMediaFiles.length < 4) {
throw new Error(`At least 4 screenshots or videos are required for publishing a new release. Found only ${previewMediaFiles.length}`)
for (const video of videos) {
const mediaPath = path.join(process.cwd(), video.uri);
if (await checkVideoSize(mediaPath)) {
throw new Error(`Video ${mediaPath} must be at least 720px in width and height.`);
}
}

if (screenshots.length + videos.length < 4) {
throw new Error(`At least 4 screenshots or videos are required for publishing a new release. Found only ${screenshots.length + videos.length}`)
}

validateLocalizableResources(config);
Expand Down Expand Up @@ -174,6 +201,13 @@ const checkImageExtension = (uri: string): boolean => {
);
};

const checkVideoExtension = (uri: string): boolean => {
const fileExt = path.extname(uri).toLowerCase();
return (
fileExt == ".mp4"
);
};

/**
* We need to pre-check some things in the localized resources before we move forward
*/
Expand Down Expand Up @@ -206,6 +240,19 @@ const checkIconDimensions = async (iconPath: string): Promise<boolean> => {
return size?.width != size?.height || (size?.width ?? 0) != 512;
};

const checkScreenshotSize = async (imagePath: string): Promise<boolean> => {
const size = await runImgSize(imagePath);

return (size?.width ?? 0) < 1080 || (size?.height ?? 0) < 1080;
}

const checkVideoSize = async (imagePath: string): Promise<boolean> => {
const size = await getVideoDimensions(imagePath);

return (size?.width ?? 0) < 720 || (size?.height ?? 0) < 720;
}


const getAndroidDetails = async (
aaptDir: string,
apkPath: string
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@types/debug": "^4.1.7",
"@types/mime": "^3.0.1",
"@types/node-fetch": "^2.6.2",
"get-video-dimensions": "^1.0.0",
"json-schema-to-typescript": "^11.0.2",
"shx": "^0.3.4"
},
Expand Down
24 changes: 18 additions & 6 deletions packages/core/src/create/ReleaseCore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Constants, mintNft } from "../CoreUtils.js";
import * as util from "util";
import { metaplexFileReplacer, validateRelease } from "../validate/CoreValidation.js";
import { imageSize } from "image-size";
import getVideoDimensions from "get-video-dimensions";

import type { Keypair, PublicKey } from "@solana/web3.js";
import type {
Expand Down Expand Up @@ -46,14 +47,25 @@ const getFileMetadata = async (item: Media | File) => {
};

const getMediaMetadata = async (item: Media) => {
const size = await runImgSize(item.uri ?? "");
const metadata = await getFileMetadata(item);

return {
...metadata,
width: size?.width ?? 0,
height: size?.height ?? 0,
};
if (item.purpose == "screenshot" || item.purpose == "icon") {
const size = await runImgSize(item.uri ?? "");

return {
...metadata,
width: size?.width ?? 0,
height: size?.height ?? 0,
};
} else {
const size = await getVideoDimensions(item.uri ?? "");

return {
...metadata,
width: size?.width ?? 0,
height: size?.height ?? 0,
};
}
};

export const createReleaseJson = async (
Expand Down
25 changes: 22 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 203bb06

Please sign in to comment.