YouTube Videolarını Daha Dar Sürelere Göre Filtreleyen Bir React Chrome Uzantısı Oluşturun – JSManifest

YouTube Videolarını Daha Dar Sürelere Göre Filtreleyen Bir React Chrome Uzantısı Oluşturun – JSManifest

Bu yazıda, Facebook’u kullanarak tepki olarak bir chrome uzantısının nasıl oluşturulacağını inceleyeceğiz. oluştur-tepki-uygulaması bize donatılacak yetenekler verecek olan araç. Bu, yapabileceğiniz anlamına gelir npm install favori düğüm modüllerinizi seçin ve bunları krom uzantılarınızı geliştirmek için kullanın. Kodumuzu doğrudan bir sayfaya enjekte edeceğiz ve ona erişimimiz olacak. document.

Uzantımızın, bir web sayfasına sağ tıkladığımızda görünen özel bir menü öğesi sunmasını sağlayacağız. Odak noktamız, arama sonuçları aracılığıyla bir youtube’un videolar sayfasında olacaktır. Arama sonuçları aracılığıyla videoları görüntülerken, uzantımız video süresinin belirli bir minimum süreden az veya belirli bir maksimum süreden yüksek olduğu durumlarda videoları sürekli olarak sonuçlardan kaldıracaktır. Bu yüzden sürekli aşağı kaydırdığımızda ve youtube sürekli bize yeni videolar beslediğinde, uzantımız sürekli görmek istemediğimiz videoları kaldıracak 🙂

“Amaç ne?” diye sorabilirsiniz. youtube zaten süre için bir filtre verdiğinde. Bu doğrudur, ancak kullanıcıların yalnızca 4 dakikadan kısa veya 20 dakikadan uzun süreleri filtrelemesine izin verir. Sizi bilmem ama süresi 8 ila 15 dakika arasında olan videoları filtrelemek gibi daha dar bir şeyi filtrelemenin inanılmaz derecede güçlü olduğunu düşünüyorum.

Ya sadece 5 ila 10 dakika arasında bir süreye sahip videoları görmek istiyorsak? Gerçek suç kanal? 4 dakikadan kısa veya 20 dakikadan uzun videoları filtrelemek tamamen işe yaramaz. 5-10 dakika arası videolar görmek istiyoruz parçalara ayrılmış bölümleri ararken 1. bölümün 4. bölümü, 2. bölümün, 3. bölümün vb. beğenin çünkü bu videolar genellikle ortalama 6 dakika sürüyor. Arama sonuçlarımıza bakarken 40 dakikalık podcast videolarıyla bombardımana tutulmak istemiyoruz.

Ayrıca, ne kadar basit olabileceğini görmek için araç çubuğundaki simgesine tıkladığınızda bir açılır pencerenin yanı sıra bir seçenekler sayfası da oluşturacağız.

(GitHub deposunun bağlantısını istiyorsanız, burada)

Bu gönderi, krom uzantılarının nasıl çalıştığının üzerinden geçmeyecek, bu yüzden daha fazla okumadan önce bunu göz önünde bulundurarak onların üzerinden geçmenizi tavsiye ederim. genel bakış Bu öğreticinin geri kalanını anlamak için gereken temel bir anlayışa sahip olmak.

Ve son olarak, bu eğitimin sonunda, muhtemelen bu yazıda inşa edeceğimiz şeyin tepki vermeye bile ihtiyacı olmadığını fark edeceksiniz. Ancak asıl mesele, kendi başınıza başlamanız için tepkinin nasıl uygulanabileceğini göstermektir.

Lafı fazla uzatmadan başlayalım!

Kod yapımız

Genel olarak krom uzantıları oluşturduğumuzda, içerik komut dosyaları koddan uzak arka plan komut dosyaları. Bu nedenle, kod paketlemenin avantajlarını ve paketleyicileri kullanan modern projelerde bulacağınız diğer özellikleri korumak istiyorsak, kodumuzu iki ayrı kod tabanında geliştirmek için birkaç ek adım gerekir.

Ayrıca tepki bileşenlerimizi doğrudan bir web sayfasına enjekte edeceğiz, böylece ona erişebiliriz. document DOM’yi değiştirebilmemiz için body nesnesi.

projeyi oluştur

Yapacağımız ilk şey, bir oluştur-tepki-uygulaması proje. Yeni projemize bir isim vermemiz gerekecek ve bu derste projemize bir isim vereceğiz “react-chrome-ext“.

Bunu terminale girelim:

npx create-react-app react-chrome-ext

Şimdi bittikten sonra dizini girin:

Yapacağımız ilk şey, bu eğitim için ihtiyacımız olmayan şeylerden kurtulmak. Temizlemeden sonra proje dizinimiz:

Uzantımızın mevcut bir sekmeye erişmesi için bir yol sağlamamız gerekiyor. document uzantımız kullanıldığında. Tepki bileşenlerimiz büyük olasılıkla henüz bu tür bir erişime sahip olmayacak çünkü kimliğe sahip bir öğeye enjekte ediliyor. root açtığımızda gördüğümüz gibi index.js:

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'

ReactDOM.render(<App />, document.getElementById('root'))

Olduğu gibi bırakırsak, uzantımız yalnızca bir web sayfasında kimliği olan gerçek bir DOM öğesi olduğunda çalışabilecektir. 'root'. Bunu biraz tersine çevireceğiz içine kendi elementimizi enjekte etmek document.body yürütmeden önce ReactDOM.render.

Bunu yapmak için bir eleman oluşturacağız ve onu document.body:

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'

const rootEl = document.createElement('div')
rootEl.id = 'react-chrome-ext'
document.body.appendChild(rootEl)

ReactDOM.render(<App />, rootEl)

Şimdi içeri gireceğiz App bileşen ve bu, uzantımız için özel kod mantığımızı uygulamaya başlayacağımız yerdir (Not: Bu, temelde bizim içerik komut dosyamızdır).

Unutmayın, bu uzantıyı bir youtube’un arama özelliklerini kullanarak video listesi için yapıyoruz. Bu yüzden sayfadayken, bağlam menüsünü açmak için sayfayı sağ tıklatabilmek istiyoruz ve içeride filtreleyiciyi çağırmak için tıklayabileceğimiz özel menü öğemiz olacak. Filtreleyiciyi çalıştırabilmemiz için içerik komut dosyalarımızın click olayını dinlemesini istiyoruz ve bunun için bağlam menüsünü arka plan komut dosyaları aracılığıyla kaydetmemiz ve tıklama olay dinleyicisini buraya eklememiz gerekiyor. Geri arama başlatıldığında, kromu kullanacağız İleti api, sinyali içerik komut dosyalarına göndermek için. Mesajlar için içerik tarafına bir dinleyici eklediğimiz için tıklama işlemini bu şekilde algılayacaktır.

İçinde App.js dinleyicileri bir React.useEffect şöyle:

import React from 'react'

function App() {
  React.useEffect(() => {
    
    
    chrome.runtime.onMessage.addListener((action) => {
      switch (action.type) {
        case 'filter-by-duration': {
          console.log('received click event from context menu')
          break
        }
        default:
          break
      }
    })
  }, [])

  return null
}

export default App

chrome.runtime.onMessage arka plan komut dosyamızdan gelen herhangi bir mesajı dinler.

Daha sonra adında bir dizin oluşturacağız. erkek arkadaş içinde kaynak dizini oluşturun ve background.js içindeki dosya şöyle:

arkaplan.js

Bu, uzantının kurulum sırasında menü öğelerini bağlam menüsüne kaydetmesi ve ayrıca tıklandığında ne olacağı için kod uygulamamız gereken yerdir:


chrome.runtime.onInstalled.addListener((message) => {
  const contexts = [
    'page',
    'selection',
    'link',
    'editable',
    'image',
    'video',
    'audio',
  ]
  
  chrome.contextMenus.create({
    title: 'Filter by duration',
    id: 'filter-by-duration',
    contexts: [...contexts, 'browser_action'],
  })
})

function getActiveTab(callback) {
  chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
    const activeTab = tabs[0]
    callback(activeTab)
  })
}


chrome.contextMenus.onClicked.addListener((info) => {
  console.log(info)
  if (info.menuItemId === 'filter-by-duration') {
    getActiveTab((tab) => {
      if (info.menuItemId === 'filter-by-duration') {
        chrome.tabs.sendMessage(tab.id, {
          type: 'filter-by-duration',
          ...info,
        })
      }
    })
  }
})

bu chrome.runtime.onInstalled.addListener((message) => { hat, uzantı kurulduğunda aranacak geri aramamızı kaydeder. Burada gördüğümüz gibi bağlam menüsünü burada oluşturuyoruz:


chrome.contextMenus.create({
  title: 'Filter by duration',
  id: 'filter-by-duration',
  contexts: [...contexts, 'browser_action'],
})

Bu kod parçası daha sonra bu menü öğesini oluşturacaktır (altta):

kurulumda tepki chrome uzantısı bağlam menüsü

biz yarattık getActiveTab gelecekte ek eylemler için yeniden kullanabilmemiz için yardımcı işlevi. Geçtiği geri aramayı çağırır ve size bulunduğunuz sekmeyi temsil eden bir nesne verir.

Ve son olarak, aşağıda gördüğümüz gibi menü maddesi tıklandığında click olayını işlemek için işleyiciyi ekledik:


chrome.contextMenus.onClicked.addListener((info) => {
  console.log(info)
  if (info.menuItemId === 'filter-by-duration') {
    getActiveTab((tab) => {
      if (info.menuItemId === 'filter-by-duration') {
        chrome.tabs.sendMessage(tab.id, {
          type: 'filter-by-duration',
          ...info,
        })
      }
    })
  }
})

Bakılması gereken önemli kısım şudur:

chrome.tabs.sendMessage(tab.id, {
  type: 'filter-by-duration',
  ...info,
})

Bu, olayı şu adrese gönderir: içerik komut dosyaları (ki bizim App bileşen alacaktır).

Bu neden sahip olduğumuzu açıklıyor chrome.runtime.onMessage.addListener satırda App bileşen:

import React from 'react'

function App() {
  React.useEffect(() => {
    
    
    chrome.runtime.onMessage.addListener((action) => {
      switch (action.type) {
        case 'filter-by-duration': {
          console.log('received click event from context menu')
          break
        }
        default:
          break
      }
    })
  }, [])

  return null
}

export default App

Şimdi switch ifadesinin içine videoları süreye göre filtreleme mantığını ekleyeceğiz. İsteğe bağlı olarak sekmeyi görüntülerken filtrenin süre değerini değiştirmenin bir yolunu sağlamak gibi sonunda uygulamak isteyeceğiniz ekstra özellikleri kodlamayacağız çünkü bu sizin için. Bu eğitimin iyiliği için sadece süreyi sabit kodlayacağız.

devam etmeden önce Youtube ve bir şey arayın. Bu eğitim için sadece arayacağız yol öfkesi. İşte aldığımız şey:

youtube yol öfke tepki krom uzantısı javascript

Filtreleyicimizde minimum 10 dakikalık ve maksimum 15 dakikalık bir süreyi sabit kodlayacağız, bu nedenle filtreyi kullandığımızda ekran görüntüsüne bakarak ilk videoyu görememeliyiz (23:42) ve dördüncü video (9:02).

Bunu başarmak için sayfanın bilgilerini sorgulamalı ve geçmeliyiz. document nesne. Sayfaya sağ tıklayıp Elemanı İncele gibi seçicileri kullanarak ihtiyacınız olan öğeleri nasıl hedefleyeceğinizi anlayabilirsiniz. Document.querySelector (Ya da aşağıdaki snippet’imi kopyalayabilirsiniz). Videonun süresini gösteren öğeyi hedef almamız ve bir sayıya dönüştürmemiz gerekiyor (çünkü bunlar dizeler), böylece amacımıza ulaşmak için matematik işlemleri uygulayabiliriz.

Şimdi devam edelim ve filtreyi uygulayalım:

const convertToMs = (ms, type) => {
  switch (type) {
    case 'seconds':
      return ms * 1000
    case 'minutes':
      return ms * 60000
    case 'hours':
      return ms * 36000000
    default:
      break
  }
}

function filterByDuration(duration) {
  return () => {
    const container = document.querySelector(
      '#contents.style-scope.ytd-item-section-renderer',
    )
    const elemsList = container.querySelectorAll('ytd-video-renderer')
    elemsList.forEach((elem) => {
      const durationElem = elem.querySelector(
        'span.style-scope.ytd-thumbnail-overlay-time-status-renderer',
      )
      if (durationElem) {
        
        let durationTime = durationElem.innerText.trim()
        const durationParts = durationTime.split(':')
        let hour = 0
        let min = 0
        let sec = 0
        switch (durationParts.length) {
          case 2:
            min = Number(durationParts[0])
            sec = Number(durationParts[1])
            break
          case 3:
            hour = Number(durationParts[0])
            min = Number(durationParts[1])
            sec = Number(durationParts[3])
            break
          default:
            break
        }
        let currentDurationInMs = convertToMs(hour, 'hours')
        currentDurationInMs += convertToMs(min, 'minutes')
        currentDurationInMs += convertToMs(sec, 'seconds')
        const minMs = convertToMs(duration.min, 'minutes')
        const maxMs = convertToMs(duration.max, 'minutes')
        if (currentDurationInMs < minMs || currentDurationInMs > maxMs) {
          elem.parentNode.removeChild(elem)
        }
      }
    })
  }
}

React.useEffect(() => {
  
  
  chrome.runtime.onMessage.addListener((action) => {
    switch (action.type) {
      case 'filter-by-duration': {
        const filter = filterByDuration({ min: 10, max: 15 })
        
        
        filter()
        
        window.addEventListener('scroll', filter)
        break
      }
      default:
        break
    }
  })
}, [])

Bu, uzantımızın çalışması için yeterli kod olmalı, ancak uzantımızı kroma yüklemeden önce birkaç şey daha yapmamız gerekiyor.

Yapmak isteyeceğimiz bir şey, ne zaman şikayet eden eslint hatasından kurtulmaktır. chrome is not defined. ekleyerek çözebiliriz webextensions: true bizim için eslintConfig içindeki mülk package.json:

"eslintConfig": {
    "extends": "react-app",
    "env": {
      "webextensions": true
    }
  }

Sonra bizim düzenlemek zorunda kalacağız manifest.json dosyamız public dizin. Biz ne zaman inşa etmek projemiz, bu manifest.json dosya üzerine kopyalanır build chrome’a ​​yükleyeceğiniz dizin olan dizin. biraz temizleyelim böylece chrome uzantımızı anlayabilir:

{
  "manifest_version": 2,
  "version": "1.0.1",
  "name": "React Chrome Extension",
  "content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "permissions": ["activeTab", "tabs", "contextMenus"]
}

Ayrıca bir belirtmemiz gerekiyor content_scripts chrome’un onları almasını istiyorsak, bildirimdeki özellik. Tipik olarak burası, bizim gibi içerik komut dosyalarımızı girdiğimiz yerdir. App.js dosya, ancak buradaki sorun, kromun aktarılmamış tepki kodunu anlamamasıdır. Bu yüzden, gönderilen çıktı dosyalarını aktarmamız gerekiyor. build çalıştırdığımızda klasör npm run build.

Devam edelim ve koşalım npm run build. Derleme klasörümüz aşağıdaki gibi görünecek:

build tepki chrome uzantısı

Manifest’e dahil etmek istediğimiz javascript dosyaları şu üç dosyadır:

  1. static/js/2.2e3b5afd.chunk.js
  2. static/js/main.bf10c391.chunk.js
  3. static/js/runtime-main.0741577f.js

…sonuç şuna benzer:

{
  "manifest_version": 2,
  "version": "1.0.1",
  "name": "React Chrome Extension",
  "content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": [
        "/static/js/2.2e3b5afd.chunk.js",
        "/static/js/main.bf10c391.chunk.js",
        "/static/js/runtime-main.0741577f.js"
      ]
    }
  ],
  "permissions": ["activeTab", "tabs", "contextMenus"]
}

Bu iyi, ama şimdi sorunumuz şu ki, her koştuğumuzda npm run build bu javascript dosyalarının dosya adı değişir, bu da dosya adındaki dinamik güncellemelerden haberdar olmak için bu satırları manuel olarak değiştirmemiz gerektiği anlamına gelir. Bu zayıf bir geliştirme deneyimi, bu yüzden bunu aşmamız gerekecek. fırlatma çıktının nasıl üretildiğini kontrol etme projemiz.

Devam et ve koş npm run eject

Bunu yaptıktan sonra, kendinize gidin config klasör ve aç webpack.config.js

için bir arama yapın .[hash:8] ve her iki oluşumu da kaldırın.

Birincisi name: 'static/media/[name].[hash:8].[ext]', öyleyse değiştir name: 'static/media/[name].[ext]', ve diğeri için aynısını yapın.

Şimdi başka bir arama yapın ve arayın .[contenthash:8] ve bunların tüm oluşumlarını da silin. Senin js dosyalar artık her çalıştırdığınızda aynı dosya adına sahip olacak. build emretmek.

Yani şimdi koştuğunda npm run build bu çıktı dosyaları her seferinde aynı kalır:

tepki krom uzantısı cra çıkarıldı

Bunları artık güvenli bir şekilde manifest.json:

{
  "manifest_version": 2,
  "version": "1.0.1",
  "name": "React Chrome Extension",
  "content_security_policy": "script-src 'self' 'sha256-xr+HqUtnq8KF3IBn+TQ37Vz0elxg11bPYmNJy5M/p38='; object-src 'self'",
  "background": {
    "scripts": ["background.js"],
    "persistent": false
  },
  "content_scripts": [
    {
      "matches": ["<all_urls>"],
      "js": [
        "/static/js/2.chunk.js",
        "/static/js/main.chunk.js",
        "/static/js/runtime-main.js"
      ]
    }
  ],
  "permissions": ["activeTab", "tabs", "contextMenus"]
}

Harika! Şimdi koş npm run build ve bunu kroma yükleyelim. Yazın chrome:extensions adres çubuğunuza, ardından “Paketlenmemiş yük” düğmesini seçin ve build dizin.

Uzantınız şimdi yüklenmelidir!

Hadi gidelim www.youtube.com ve ara “yol öfkesi”. Sayfaya sağ tıklayın ve tıklayın “Süreye göre filtrele”. Buna tıkladıktan sonra, uzantı artık süre filtrenize göre öğeleri ekrandan kaldırmalıdır! Yaşasın!

Hatırlayın, önceki ekran görüntülerimizden birinde birkaç video sonucumuz vardı ve video süresinden bahsetmiştik. 23:54 ve 9:42 filtremiz uygulandığında gösterilmemeli mi?

Bakalım bu doğru mu:

tepki krom uzantısı youtube süresi filtre sonucu

Yaşasın!

Bu öğreticiyi bitirmeden önce devam edelim ve bir seçenekler sayfanın yanı sıra bir açılır.

Seçenekler sayfası, sağ tık araç çubuğunda uzantınızın simgesini tıklayın ve seçenekler öğe.

Açılır pencere benzer şekilde kullanılır. sol tık araç çubuğundaki uzantınızın simgesi.

sadece bir tane oluşturabiliriz options.html ve popup.html içinde src/bg/ aşağıdaki gibi:

seçenekler açılır pencere tepki krom uzantısı

O zaman bir giriş yapabiliriz postbuild bizim için komut dosyası package.json bina tamamlandıktan sonra otomatik olarak çalışan:

"scripts": {
    "start": "node scripts/start.js",
    "prebuild": "rm -rf build",
    "build": "node scripts/build.js",
    "postbuild": "cp src/bg/* build"
}

Çözüm

Ve bu yazının sonu burada bitiyor! Umarım bunu değerli bulmuşsunuzdur ve gelecekte daha fazlasını ararsınız!

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.