diff --git a/.github/workflows/release-edge.yml b/.github/workflows/release-edge.yml index cfebfb56..dc0fef8a 100644 --- a/.github/workflows/release-edge.yml +++ b/.github/workflows/release-edge.yml @@ -34,6 +34,7 @@ jobs: token: ${{ secrets.BOT_TOKEN }} release-type: node release-as: ${{ steps.calculate-edge-version.outputs.next-edge }} + prerelease: true default-branch: ${{ github.ref_name }} # The logic below handles the npm publication: diff --git a/.github/workflows/release-manual.yml b/.github/workflows/release-manual.yml new file mode 100644 index 00000000..ace7463a --- /dev/null +++ b/.github/workflows/release-manual.yml @@ -0,0 +1,85 @@ +name: 🔧 Release (Manual) + +on: + workflow_dispatch: + inputs: + release-as: + description: 'Release Version' + required: true + release-type: + description: 'Release Type' + type: choice + required: true + default: 'edge' + options: + - edge + - latest + +jobs: + release: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ github.event.inputs.release-type == 'latest' && 'master' || 'edge'}} + + - run: npm ci + + - name: Release PR + uses: google-github-actions/release-please-action@v3 + id: release + with: + token: ${{ secrets.BOT_TOKEN }} + release-type: node + release-as: ${{ github.event.inputs.release-as }} + prerelease: ${{ github.event.inputs.release-type == 'edge'}} + default-branch: ${{ github.event.inputs.release-type == 'latest' && 'master' || 'edge'}} + + # The logic below handles the npm publication: + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + if: ${{ steps.release.outputs.release_created }} + # these if statements ensure that a publication only occurs when + # a new release is created: + - run: npm run build-all + if: ${{ steps.release.outputs.release_created }} + - run: npm publish --tag ${{ github.event.inputs.release-type }} + env: + NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}} + if: ${{ steps.release.outputs.release_created }} + + - name: Set Notification Messages + id: set-messages + if: steps.release.outputs.release_created + run: | + if [[ ${{ job.status }} == "success" ]]; then + echo "SLACK_TITLE=Video Player ${{ steps.release.outputs.tag_name }} Deployed" >> $GITHUB_OUTPUT + echo "SLACK_MESSAGE=Success :rocket: cloudinary-video-player version ${{ steps.release.outputs.tag_name }} deployed successfully" >> $GITHUB_OUTPUT + echo "SLACK_FOOTER=Check it out at https://cloudinary.github.io/cloudinary-video-player/?ver=${{ github.event.inputs.release-type }}&min=true" >> $GITHUB_OUTPUT + else + echo "SLACK_TITLE=Video Player Deployment Failed" >> $GITHUB_OUTPUT + echo "SLACK_MESSAGE=:alert: Failed to deploy cloudinary-video-player version ${{ steps.release.outputs.tag_name }}" >> $GITHUB_OUTPUT + echo "SLACK_FOOTER=See log here https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}/job/${{ github.job }}" >> $GITHUB_OUTPUT + fi + shell: bash + + - name: Slack Notification + if: steps.release.outputs.release_created + uses: rtCamp/action-slack-notify@v2.2.0 + env: + SLACK_WEBHOOK: ${{ vars.FE_DEPLOYMENTS_SLACK_WEBHOOK }} + SLACK_CHANNEL: 'rnd-fe-releases' + SLACK_COLOR: ${{ job.status }} + SLACK_TITLE: ${{ steps.set-messages.outputs.SLACK_TITLE }} + SLACK_MESSAGE: ${{ steps.set-messages.outputs.SLACK_MESSAGE }} + SLACK_FOOTER: ${{ steps.set-messages.outputs.SLACK_FOOTER }} + + - uses: gacts/purge-jsdelivr-cache@v1 + if: steps.release.outputs.release_created + with: + url: | + https://cdn.jsdelivr.net/npm/cloudinary-video-player + https://cdn.jsdelivr.net/npm/cloudinary-video-player@edge diff --git a/package-lock.json b/package-lock.json index 84fd9efc..0034cfc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "license": "MIT", "dependencies": { "@cloudinary/url-gen": "^1.19.0", - "cloudinary-video-analytics": "1.5.0", + "cloudinary-video-analytics": "1.6.0", "lodash": "^4.17.21", "uuid": "^9.0.1", "video.js": "^8.11.8", @@ -6278,9 +6278,9 @@ } }, "node_modules/cloudinary-video-analytics": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cloudinary-video-analytics/-/cloudinary-video-analytics-1.5.0.tgz", - "integrity": "sha512-CxQonA3lOeZrtapnbg7Gs7IBDZrujgiikcbXzBMTVGRNWIzovCtYUnddTMDCqTlz7UwhRkC/gMlYzMDwnZeRpQ==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/cloudinary-video-analytics/-/cloudinary-video-analytics-1.6.0.tgz", + "integrity": "sha512-SdUKK6J35RiZEyjpTzXxH4nLDAJtwj3NYa35LCLtad6EtwYrbV92myyMm96B85ogDdhjHWM6RAxJnHPkIUOPRA==", "dependencies": { "is-mobile": "^4.0.0", "uuid": "9.0.0" diff --git a/package.json b/package.json index 819f7595..d1c5b59b 100644 --- a/package.json +++ b/package.json @@ -78,7 +78,7 @@ }, "dependencies": { "@cloudinary/url-gen": "^1.19.0", - "cloudinary-video-analytics": "1.5.0", + "cloudinary-video-analytics": "1.6.0", "lodash": "^4.17.21", "uuid": "^9.0.1", "video.js": "^8.11.8", diff --git a/src/plugins/cloudinary-analytics/index.js b/src/plugins/cloudinary-analytics/index.js index 372890ef..edfec7ec 100644 --- a/src/plugins/cloudinary-analytics/index.js +++ b/src/plugins/cloudinary-analytics/index.js @@ -1,10 +1,14 @@ +import videojs from 'video.js'; import { connectCloudinaryAnalytics } from 'cloudinary-video-analytics'; import { PLAYER_EVENT } from '../../utils/consts'; class CloudinaryAnalytics { constructor(player) { this.player = player; - this.cloudinaryAnalytics = connectCloudinaryAnalytics(this.player.videoElement); + this.shouldUseCustomEvents = videojs.browser.IS_IOS; + this.cloudinaryAnalytics = connectCloudinaryAnalytics(this.player.videoElement, { + customEvents: this.shouldUseCustomEvents, + }); this.currentVideMetadata = { cloudName: null, publicId: null @@ -29,7 +33,31 @@ class CloudinaryAnalytics { } }; + dispatchCustomEventOnVideoPlayer = (name, detail = {}) => { + const ev = new CustomEvent(`cld-custom-${name}`, { + detail, + }); + this.player.videoElement.dispatchEvent(ev); + }; + + connectCustomEvents = () => { + this.player.on(PLAYER_EVENT.PLAY, () => this.dispatchCustomEventOnVideoPlayer('play')); + this.player.on(PLAYER_EVENT.PAUSE, () => this.dispatchCustomEventOnVideoPlayer('pause')); + this.player.on(PLAYER_EVENT.EMPTIED, () => this.dispatchCustomEventOnVideoPlayer('emptied')); + this.player.on(PLAYER_EVENT.LOADED_METADATA, () => { + const videoDuration = this.player.videoElement.duration || null; + this.dispatchCustomEventOnVideoPlayer('loadedmetadata', { + videoDuration, + }); + }); + }; + init() { + // only for iOS there is problem with reporting events because videojs re-triggers events and stops native ones + if (this.shouldUseCustomEvents) { + this.connectCustomEvents(); + } + this.player.on(PLAYER_EVENT.CLD_SOURCE_CHANGED, this.sourceChanged); } } diff --git a/src/utils/consts.js b/src/utils/consts.js index 5521e407..e70f7151 100644 --- a/src/utils/consts.js +++ b/src/utils/consts.js @@ -10,6 +10,7 @@ export const PLAYER_EVENT = { PAUSE_NO_SEEK: 'pausenoseek', ERROR: 'error', TIME_UPDATE: 'timeupdate', + EMPTIED: 'emptied', RETRY_PLAYLIST: 'retryplaylist', CAN_PLAY_THROUGH: 'canplaythrough', CLD_SOURCE_CHANGED: 'cldsourcechanged',