Skip to content

Instantly share code, notes, and snippets.

@Kcko
Created May 28, 2025 07:44
Show Gist options
  • Save Kcko/8a7f8e95f6475924f8c51934ce3b329f to your computer and use it in GitHub Desktop.
Save Kcko/8a7f8e95f6475924f8c51934ce3b329f to your computer and use it in GitHub Desktop.

Vue.js Media Transformer - Všechny varianty implementace

1. Composable (Vue 3 Composition API)

// composables/useMediaObjects.js
export function useMediaObjects() {
  const transformMediaObjects = (productGallery, productVideos) => {
    const finalObjects = []

    // Photos
    if (productGallery) {
      finalObjects.push(
        ...productGallery.map((photo, index) => ({
          ...photo,
          type: 'photo',
          rank: index + 1
        }))
      )
    }

    // Videos
    if (productVideos) {
      finalObjects.push(
        ...productVideos.map((videoUrl, index) => {
          const youtubeId = extractYouTubeId(videoUrl)
          return {
            url: videoUrl,
            type: 'video',
            rank: finalObjects.length + index + 1,
            previewThumb: youtubeId 
              ? `https://img.youtube.com/vi/${youtubeId}/sddefault.jpg` 
              : null
          }
        })
      )
    }

    return finalObjects
  }

  const extractYouTubeId = (url) => {
    return url.match(
      /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
    )?.[1]
  }

  return {
    transformMediaObjects,
    extractYouTubeId
  }
}

Použití v komponentě:

// Product.vue
<script setup>
import { computed } from 'vue'
import { useMediaObjects } from '@/composables/useMediaObjects'

const props = defineProps(['productGallery', 'product'])

const { transformMediaObjects } = useMediaObjects()

const mediaObjects = computed(() => {
  return transformMediaObjects(props.productGallery, props.product?.product_video)
})
</script>

2. JS Třída - Statické metody

// services/MediaTransformer.js
export class MediaTransformer {
  static transform(productGallery, productVideos) {
    const finalObjects = []

    if (productGallery) {
      finalObjects.push(
        ...productGallery.map((photo, index) => ({
          ...photo,
          type: 'photo',
          rank: index + 1
        }))
      )
    }

    if (productVideos) {
      finalObjects.push(
        ...productVideos.map((videoUrl, index) => {
          const youtubeId = this.extractYouTubeId(videoUrl)
          return {
            url: videoUrl,
            type: 'video',
            rank: finalObjects.length + index + 1,
            previewThumb: youtubeId 
              ? `https://img.youtube.com/vi/${youtubeId}/sddefault.jpg` 
              : null
          }
        })
      )
    }

    return finalObjects
  }

  static extractYouTubeId(url) {
    return url.match(
      /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
    )?.[1]
  }

  static generateThumbnail(youtubeId, quality = 'sddefault') {
    return `https://img.youtube.com/vi/${youtubeId}/${quality}.jpg`
  }
}

Použití:

// Product.vue
<script setup>
import { computed } from 'vue'
import { MediaTransformer } from '@/services/MediaTransformer'

const props = defineProps(['productGallery', 'product'])

const mediaObjects = computed(() => {
  return MediaTransformer.transform(props.productGallery, props.product?.product_video)
})
</script>

3. JS Třída - Export třídy (instance v komponentě)

// services/MediaTransformer.js
export class MediaTransformer {
  constructor(config = {}) {
    this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
    this.defaultVideoType = config.defaultVideoType || 'video'
  }

  transform(productGallery, productVideos) {
    const finalObjects = []

    if (productGallery) {
      finalObjects.push(
        ...productGallery.map((photo, index) => ({
          ...photo,
          type: 'photo',
          rank: index + 1
        }))
      )
    }

    if (productVideos) {
      finalObjects.push(
        ...productVideos.map((videoUrl, index) => {
          const youtubeId = this.extractYouTubeId(videoUrl)
          return {
            url: videoUrl,
            type: this.defaultVideoType,
            rank: finalObjects.length + index + 1,
            previewThumb: youtubeId 
              ? `https://img.youtube.com/vi/${youtubeId}/${this.thumbnailQuality}.jpg` 
              : null
          }
        })
      )
    }

    return finalObjects
  }

  extractYouTubeId(url) {
    return url.match(
      /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
    )?.[1]
  }

  setConfig(newConfig) {
    Object.assign(this, newConfig)
    return this
  }
}

Použití:

// Product.vue
<script setup>
import { computed, ref } from 'vue'
import { MediaTransformer } from '@/services/MediaTransformer'

const props = defineProps(['productGallery', 'product'])

const mediaTransformer = ref(new MediaTransformer({ thumbnailQuality: 'hqdefault' }))

const mediaObjects = computed(() => {
  return mediaTransformer.value.transform(props.productGallery, props.product?.product_video)
})
</script>

4. JS Třída - Export instance (singleton)

// services/MediaTransformer.js
class MediaTransformer {
  constructor(config = {}) {
    this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
  }

  transform(productGallery, productVideos) {
    // stejná implementace jako výše...
  }

  extractYouTubeId(url) {
    // stejná implementace...
  }

  setConfig(newConfig) {
    Object.assign(this, newConfig)
    return this
  }
}

// Export instance
export const mediaTransformer = new MediaTransformer()

// Případně export obou
export { MediaTransformer }

Použití:

// Product.vue
<script setup>
import { computed } from 'vue'
import { mediaTransformer } from '@/services/MediaTransformer'

const props = defineProps(['productGallery', 'product'])

const mediaObjects = computed(() => {
  return mediaTransformer.transform(props.productGallery, props.product?.product_video)
})

// Změna konfigurace kdykoliv:
// mediaTransformer.setConfig({ thumbnailQuality: 'maxresdefault' })
</script>

5. Singleton Pattern

// services/MediaTransformer.js
class MediaTransformer {
  static _instance = null
  
  constructor(config = {}) {
    if (MediaTransformer._instance) {
      return MediaTransformer._instance
    }
    
    this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
    MediaTransformer._instance = this
  }
  
  static getInstance(config = {}) {
    if (!this._instance) {
      this._instance = new MediaTransformer(config)
    }
    return this._instance
  }

  transform(productGallery, productVideos) {
    // implementace...
  }

  extractYouTubeId(url) {
    // implementace...
  }
}

export default MediaTransformer

Použití:

// Product.vue
<script setup>
import { computed } from 'vue'
import MediaTransformer from '@/services/MediaTransformer'

const props = defineProps(['productGallery', 'product'])

const mediaObjects = computed(() => {
  const transformer = MediaTransformer.getInstance({ thumbnailQuality: 'hqdefault' })
  return transformer.transform(props.productGallery, props.product?.product_video)
})
</script>

6. Factory Function

// services/MediaTransformer.js
class MediaTransformer {
  constructor(config = {}) {
    this.thumbnailQuality = config.thumbnailQuality || 'sddefault'
  }

  transform(productGallery, productVideos) {
    // implementace...
  }

  extractYouTubeId(url) {
    // implementace...
  }
}

export const createMediaTransformer = (config = {}) => {
  return new MediaTransformer(config)
}

// Export i třídy pro pokročilé použití
export { MediaTransformer }

Použití:

// Product.vue
<script setup>
import { computed, ref } from 'vue'
import { createMediaTransformer } from '@/services/MediaTransformer'

const props = defineProps(['productGallery', 'product'])

const mediaTransformer = ref(createMediaTransformer({ thumbnailQuality: 'maxresdefault' }))

const mediaObjects = computed(() => {
  return mediaTransformer.value.transform(props.productGallery, props.product?.product_video)
})
</script>

7. Plain Object/Service

// services/mediaService.js
export const mediaService = {
  defaultConfig: {
    thumbnailQuality: 'sddefault'
  },

  transform(productGallery, productVideos, config = {}) {
    const finalConfig = { ...this.defaultConfig, ...config }
    const finalObjects = []

    if (productGallery) {
      finalObjects.push(
        ...productGallery.map((photo, index) => ({
          ...photo,
          type: 'photo',
          rank: index + 1
        }))
      )
    }

    if (productVideos) {
      finalObjects.push(
        ...productVideos.map((videoUrl, index) => {
          const youtubeId = this.extractYouTubeId(videoUrl)
          return {
            url: videoUrl,
            type: 'video',
            rank: finalObjects.length + index + 1,
            previewThumb: youtubeId 
              ? `https://img.youtube.com/vi/${youtubeId}/${finalConfig.thumbnailQuality}.jpg` 
              : null
          }
        })
      )
    }

    return finalObjects
  },

  extractYouTubeId(url) {
    return url.match(
      /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
    )?.[1]
  }
}

Použití:

// Product.vue
<script setup>
import { computed } from 'vue'
import { mediaService } from '@/services/mediaService'

const props = defineProps(['productGallery', 'product'])

const mediaObjects = computed(() => {
  return mediaService.transform(
    props.productGallery, 
    props.product?.product_video,
    { thumbnailQuality: 'hqdefault' }
  )
})
</script>

8. Pure Functions (Helper)

// utils/mediaTransform.js
export const transformMediaObjects = (productGallery, productVideos, config = {}) => {
  const { thumbnailQuality = 'sddefault' } = config
  const finalObjects = []

  if (productGallery) {
    finalObjects.push(
      ...productGallery.map((photo, index) => ({
        ...photo,
        type: 'photo',
        rank: index + 1
      }))
    )
  }

  if (productVideos) {
    finalObjects.push(
      ...productVideos.map((videoUrl, index) => {
        const youtubeId = extractYouTubeId(videoUrl)
        return {
          url: videoUrl,
          type: 'video',
          rank: finalObjects.length + index + 1,
          previewThumb: youtubeId 
            ? `https://img.youtube.com/vi/${youtubeId}/${thumbnailQuality}.jpg` 
            : null
        }
      })
    )
  }

  return finalObjects
}

export const extractYouTubeId = (url) => {
  return url.match(
    /(?:youtube\.com\/(?:[^\/]+\/.+\/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be\/)([^"&?\/\s]{11})/
  )?.[1]
}

Použití:

// Product.vue
<script setup>
import { computed } from 'vue'
import { transformMediaObjects } from '@/utils/mediaTransform'

const props = defineProps(['productGallery', 'product'])

const mediaObjects = computed(() => {
  return transformMediaObjects(
    props.productGallery, 
    props.product?.product_video,
    { thumbnailQuality: 'hqdefault' }
  )
})
</script>

Srovnání variant

Varianta Výhody Nevýhody Použití
Composable Vue 3 native, reaktivita, auto-import Vue specific Vue 3 projekty
Statické metody Jednoduché, žádná konfigurace Není flexibilní Jednoduché transformace
Export třídy Flexibilní konfigurace Musíš vytvářet instance Různé konfigurace
Export instance Žádné new, sdílený stav Pevná konfigurace Jednotná konfigurace
Singleton Jedna instance, lazy loading Složitější pattern Globální konfigurace
Factory Flexibilní vytváření Extra abstrakce Komplexní objekty
Plain Object Jednoduché, framework agnostic Není OOP Malé utility
Pure Functions Nejjednodušší, testovatelné Žádná organizace Funkcionální přístup

Doporučení

  • Pro jednoduché transformace: Pure Functions nebo Statické metody
  • Pro flexibilní konfiguraci: Export třídy nebo Factory
  • Pro Vue 3 projekty: Composable
  • Pro globální použití: Export instance s setConfig
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment