Hello.

I am Paul Kinlan.

A Developer Advocate for Chrome and the Open Web at Google.

Puppeteer Go

Paul Kinlan

నేను The Headless Web ప్రేమిస్తున్నాను - ఇది The Headless Web యొక్క ఆలోచనలతో The Headless Web నన్ను అనుమతిస్తుంది - ఇది వెబ్‌ను కనిపించే బ్రౌజర్ లేకుండా బ్రౌజర్‌లో DOM-curl మరియు DOM-curl (జావాస్క్రిప్ట్‌ను అమలు చేసే కర్ల్) వంటి సాధనాలను కూడా నిర్మిస్తుంది. పేజీలను స్క్రాప్ చేయడానికి, మార్చటానికి మరియు సంభాషించడానికి బ్రౌజర్‌ను స్క్రిప్ట్ చేయడం నాకు చాలా ఇష్టం.

నేను చేయాలనుకున్న ఒక డెమో Capturing 422 live images యొక్క Capturing 422 live images పోస్ట్ నుండి ప్రేరణ పొందింది, అక్కడ ఆమె ఒక తోలుబొమ్మ స్క్రిప్ట్‌ను నడిపింది, అది చాలా పేజీలకు నావిగేట్ చేస్తుంది మరియు స్క్రీన్ Capturing 422 live images తీసుకుంటుంది. చాలా పేజీలకు వెళ్లే బదులు, పేజీలోని అనేక మూలకాల స్క్రీన్‌షాట్‌లను తీసుకోవాలనుకున్నాను.

పప్పెటీర్‌తో నాకు ఉన్న సమస్య ఏమిటంటే మీరు ఏదైనా చేయవలసిన ప్రారంభ చరణం. ప్రారంభించండి, టాబ్ తెరవండి, నావిగేట్ చేయండి - ఇది సంక్లిష్టంగా లేదు, సాధారణ స్క్రిప్ట్‌ల కోసం నేను సృష్టించాలనుకుంటున్న దానికంటే ఎక్కువ బాయిలర్‌ప్లేట్. అందుకే నేను Puppeteer Go సృష్టించాను. ఇది CLI యుటిలిటీలను సులభంగా నిర్మించడంలో నాకు సహాయపడే ఒక చిన్న స్క్రిప్ట్, ఇది బ్రౌజర్‌ను తెరుస్తుంది, ఒక పేజీకి నావిగేట్ చేస్తుంది, మీ చర్య చేస్తుంది మరియు తరువాత శుభ్రపరుస్తుంది.

దాన్ని తనిఖీ చేయండి.

const { go } = require('puppeteer-go');

go('https://paul.kinlan.me', async (page) => {
    const elements = await page.$$("h1");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});

పై కోడ్ నా బ్లాగులో h1 మూలకాన్ని కనుగొని స్క్రీన్ షాట్ తీసుకుంటుంది. ఇరే యొక్క పనికి ఇది ఎక్కడా మంచిది కాదు, కాని మనం canisuse.com నుండి స్క్రీన్ షాట్లను పేజీ నుండి నేరుగా లాగగలమా అని చూడటం చక్కగా ఉందని నేను అనుకున్నాను.

const { go } = require('puppeteer-go');

go('https://caniuse.com/#search=css', async (page) => {
    const elements = await page.$$("article.feature-block.feature-block--feature");
    let count = 0;
    for(let element of elements) {
      try {
        await element.screenshot({ path: `${count++}.png`});
      } catch (err) {
        console.log(count, err);
      }
    }
});
4.png
3.png
2.png
1.png
0.png

ఆనందించండి!

Paul Kinlan

Trying to make the web and developers better.

RSS Github Medium

A simple video insertion tool for EditorJS

Paul Kinlan

నేను నిజంగా EditorJS ఇష్టపడుతున్నాను. ఇది నా స్టాటిక్ హ్యూగో బ్లాగ్ కోసం చాలా సులభమైన వెబ్-హోస్ట్ ఇంటర్‌ఫేస్‌ను సృష్టించనివ్వండి.

సాధారణ బ్లాక్-ఆధారిత ఎడిటర్‌లో ఎడిటర్‌జేఎస్‌లో నాకు చాలా అవసరం ఉంది. దీనికి శీర్షికలు, కోడ్ మరియు హోస్టింగ్ మౌలిక సదుపాయాలు అవసరం లేకుండా ఎడిటర్‌కు చిత్రాలను జోడించే సరళమైన మార్గం కోసం ప్లగిన్ ఉంది. ఇప్పటి వరకు వీడియోలను ఎడిటర్‌కు జోడించడానికి దీనికి సాధారణ మార్గం లేదు.

నేను simple-image ప్లగ్ఇన్ రిపోజిటరీని తీసుకున్నాను మరియు simple-video ప్లగ్ఇన్ ( npm module ) ను సృష్టించడానికి దానిని మార్చాను (కేవలం ఒక టాడ్). ఇప్పుడు నేను ఈ బ్లాగులో వీడియోలను సులభంగా చేర్చగలను.

మీరు ఎడిటర్‌జెఎస్‌తో ఫ్యామిలర్‌గా ఉంటే, మీ ప్రాజెక్ట్‌లలో చేర్చడం చాలా సులభం. ఈ క్రింది విధంగా ఇన్‌స్టాల్ చేయండి

npm i simple-video-editorjs

మీరు సరిపోయేటట్లు చూసేటప్పుడు దాన్ని మీ ప్రాజెక్ట్‌లో చేర్చండి.

const SimpleVideo = require('simple-video-editorjs');

var editor = EditorJS({
  ...
  
  tools: {
    ...
    video: SimpleVideo,
  }
  
  ...
});

ఎడిటర్ కొన్ని సాధారణ ఎంపికలను కలిగి ఉంది, ఇది వీడియోను పేజీలో ఎలా హోస్ట్ చేయాలో కాన్ఫిగర్ చేయడానికి మిమ్మల్ని అనుమతిస్తుంది:

  1. ఆటోప్లే - పేజీ లోడ్ అయినప్పుడు వీడియో స్వయంచాలకంగా ప్లే అవుతుంది
  2. మ్యూట్ చేయబడింది - వీడియో అప్రమేయంగా ధ్వనిని కలిగి ఉండదు (ఆటోప్లే కోసం అవసరం)
  3. నియంత్రణలు - వీడియో డిఫాల్ట్ HTML నియంత్రణలను కలిగి ఉంటుంది.

పొందుపరిచిన వీడియో యొక్క శీఘ్ర ఉదాహరణ క్రింద ఉంది (మరియు కొన్ని ఎంపికలను చూపిస్తుంది).

ఏదేమైనా, ఈ చిన్న ప్లగ్‌ఇన్‌ను సృష్టించడం నాకు చాలా ఆనందంగా ఉంది - ఇది సృష్టించడం చాలా కష్టం కాదు మరియు నేను చేసిన ఏకైక విషయం ఏమిటంటే బేస్ 64 కి మార్పిడిని వాయిదా వేయడం, ఇది సాధారణ చిత్రాలు ఉపయోగిస్తుంది మరియు బదులుగా బొట్టు URL లను ఉపయోగిస్తుంది.

Test post Video upload

Paul Kinlan

మీరు ఇక్కడ ఒక వీడియో చూస్తే, అది పని చేస్తుంది.

Read More

Friendly Project Name Generator with Zeit

Paul Kinlan

నేను వెబ్ సైట్లు సృష్టించడానికి సులభంగా చేసే ప్రాజెక్టులకు కొన్ని ఆలోచనలు పొందారు - ఆలోచనలు ఒకటి ఒక చేయడమే netlify-like drag and drop interface కోసం zeit ఆధారిత ప్రాజెక్టులు (నేను జీట్ వంటి కానీ అది విస్తరించడానికి CLI మేజిక్ ఒక చిన్న బిట్ అవసరం).

ఈ పోస్ట్ పజిల్ యొక్క ఒక చిన్న భాగాన్ని మాత్రమే కవర్ చేస్తుంది: ప్రాజెక్ట్ పేర్లను సృష్టించడం.

Glitch దీనికి మంచి ఉదాహరణ, మీరు ఒక ప్రాజెక్ట్‌ను సృష్టించినప్పుడు అది విచిత్రమైన యాదృచ్ఛికంగా ఉత్పత్తి చేయబడిన పేరును ఇస్తుంది. ఈ బృందం ఒక good dictionary of fairly safe words కూడా బాగా మిళితం చేసింది (మరియు మీకు కావాలంటే వారు హోస్ట్ చేయడానికి సాధారణ సర్వర్ కలిగి ఉంటారు).

కాబట్టి, ఈ ఆదివారం సైడ్ ప్రాజెక్ట్ జైట్ యొక్క serverless-functions మరియు గ్లిచ్ నుండి నిఘంటువు ఉపయోగించి యాదృచ్ఛిక ప్రాజెక్ట్ పేర్లను రూపొందించడానికి ఒక సాధారణ సూక్ష్మ సేవను సృష్టించడం.

And here it is ( code ), ఇది చాలా చిన్నది మరియు చాలా క్లిష్టంగా లేదు.

const words = require("friendly-words");

function generate(count = 1, separator = "-") {
  const { predicates, objects } = words;
  const pCount = predicates.length;
  const oCount = objects.length;
  const output = [];

  for (let i = 0; i < count; i++) {
    const pair = [predicates[Math.floor(Math.random() * pCount)], objects[Math.floor(Math.random() * oCount)]];
    output.push(pair.join(separator));
  }

  return output;
}

module.exports = { generate }

మీరు దీన్ని నేరుగా మీ ప్రాజెక్ట్‌లో చేర్చకూడదనుకుంటే, https: // friendly-project-name కు వెబ్ అభ్యర్థన చేయడం ద్వారా యాదృచ్ఛిక ప్రాజెక్ట్ పేర్లను ("XY" రూపంలో) రూపొందించడానికి మీరు HTTP ఎండ్ పాయింట్‌ను ఉపయోగించవచ్చు. kinlan.now.sh/api/names, ఇది కిందివాటిని తిరిగి ఇస్తుంది.

["momentous-professor"]

కౌంట్ = x యొక్క ప్రశ్న-స్ట్రింగ్ పరామితితో ఎన్ని పేర్లను ఉత్పత్తి చేయాలో కూడా మీరు నియంత్రించవచ్చు, ఉదా. Https://friendly-project-name.kinlan.now.sh/api/names?count=100

["melon-tangerine","broad-jury","rebel-hardcover","far-friend","notch-hornet","principled-wildcat","level-pilot","steadfast-bovid","holistic-plant","expensive-ulna","sixth-gear","political-wrench","marred-spatula","aware-weaver","awake-pair","nosy-hub","absorbing-petunia","rhetorical-birth","paint-sprint","stripe-reward","fine-guardian","coconut-jumbo","spangle-eye","sudden-euphonium","familiar-fossa","third-seaplane","workable-cough","hot-light","diligent-ceratonykus","literate-cobalt","tranquil-sandalwood","alabaster-pest","sage-detail","mousy-diascia","burly-food","fern-pie","confusion-capybara","harsh-asterisk","simple-triangle","brindle-collard","destiny-poppy","power-globeflower","ruby-crush","absorbed-trollius","meadow-blackberry","fierce-zipper","coal-mailbox","sponge-language","snow-lawyer","adjoining-bramble","deserted-flower","able-tortoise","equatorial-bugle","neat-evergreen","pointy-quart","occipital-tax","balsam-fork","dear-fairy","polished-produce","darkened-gondola","sugar-pantry","broad-slouch","safe-cormorant","foregoing-ostrich","quasar-mailman","glittery-marble","abalone-titanosaurus","descriptive-arch","nickel-ostrich","historical-candy","mire-mistake","painted-eater","pineapple-sassafras","pastoral-thief","holy-waterlily","mewing-humor","bubbly-cave","pepper-situation","nosy-colony","sprout-aries","cyan-bestseller","humorous-plywood","heavy-beauty","spiral-riverbed","gifted-income","lead-kiwi","pointed-catshark","ninth-ocean","purple-toucan","tundra-cut","coal-geography","icy-lunaria","agate-wildcat","respected-garlic","polar-almandine","periodic-narcissus","carbonated-waiter","lavish-breadfruit","confirmed-brand","repeated-period"]

సెపరేటర్ యొక్క ప్రశ్న-స్ట్రింగ్ పరామితితో మీరు సెపరేటర్‌ను నియంత్రించవచ్చు. అనగా, సెపరేటర్ = @, ఉదా. https://friendly-project-name.kinlan.now.sh/api/names?separator=@

["handsomely@asterisk"]

ఈ ప్రాజెక్ట్ యొక్క చాలా ఉపయోగకరమైన అంశం ఏమిటంటే, పదాల కలయిక అప్రియమైనదిగా ఉంటే, గ్లిచ్ రెపోను మళ్లీ జరగకుండా చూసుకోవడం సులభం.

ప్రాజెక్ట్ హోస్టింగ్ చాలా ఖరీదైనది కాదని uming హిస్తే నేను సేవను కొనసాగిస్తాను, కానీ మీరు ఎప్పుడైనా ఇలాంటి సూక్ష్మ సేవను సృష్టించాలనుకుంటే దాన్ని మీరే క్లోన్ చేసుకోండి.

ప్రత్యక్ష ఉదాహరణ

చర్యలో ఉన్న API యొక్క సూపర్ శీఘ్ర ఉదాహరణ క్రిందిది.

const render = (promise, elementId) => {
  promise.then(async(response) => {
    const el = document.getElementById(elementId);
    el.innerText = await response.text();
  })
};


onload = () => {
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names"), "basic");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?count=100"), "many");
  render(fetch("https://friendly-project-name.kinlan.now.sh/api/names?separator=@"), "separator");
}

ఒకే ప్రతిస్పందన



చాలా స్పందనలు



కస్టమ్ సెపరేటర్లు



{{<raw-html>}}

{{</ raw-html>}}

Frankie and Bennys: Pay for your meal via the web

Paul Kinlan

మీరు మొబైల్‌లో చెల్లించవచ్చని రెస్టారెంట్ చెప్పినప్పుడల్లా, నేను దీన్ని ఎల్లప్పుడూ తనిఖీ చేస్తాను, ఎక్కువగా మీరు అనువర్తనాన్ని ఉపయోగించాల్సిన అవసరం ఉందని నేను బాధపడుతున్నాను. QR కోడ్ వెబ్ ఆధారిత చెల్లింపుల ప్రవాహానికి దారితీసినప్పుడు నా ఆశ్చర్యాన్ని g హించుకోండి ….. మరియు అది పని చేసింది. అద్భుత పని ఫ్రాంకీ మరియు బెన్నీ! ఈ సమయంలో, నేను Google Pay ని ఎంచుకున్నాను, కానీ అది పని చేయలేదు (అంతర్గతంగా ఇమెయిల్ పంపబడింది!) బదులుగా అద్భుతమైన అంశాలు, మరియు ఇది దాదాపు ఒక నిమిషం ముగింపు వరకు ఉంది.

Read More

Podroll

Paul Kinlan

నేను పాడ్‌కాస్ట్‌లను ప్రేమిస్తున్నాను మరియు నేను చాలా కొద్దిమందిని వింటాను, అయినప్పటికీ క్రొత్త పాడ్‌కాస్ట్‌లను కనుగొనడం చాలా కష్టతరమైన ప్రక్రియ అని నేను భావిస్తున్నాను మరియు నేను వింటున్నదాన్ని పంచుకోవడానికి స్నేహితులపై ఆధారపడతాను. కాబట్టి దీన్ని దృష్టిలో podroll ఇక్కడ నా podroll . నేను ఉపయోగించే Player.fm నా మంచి స్నేహితుడు మైక్ Mahemoff ద్వారా తయారు మరియు భాగస్వామ్యం సామర్ధ్యాన్ని కలిగి ఉంది మరియు మీ చందా జాబితా ఎగుమతి. ఈ పేజీ refreshed frequently using my little script .

Read More

Adding "dark mode" to my blog

Paul Kinlan

నేను జెరెమీ కీత్ యొక్క post about adding dark mode to his blog మరియు ఇది చాలా సరళంగా అనిపించింది, కాబట్టి నేను దానిని ఒక గిరగిరా ఇవ్వాలని నిర్ణయించుకున్నాను. అందరూ చూడటానికి ఇక్కడ diff of the work . ఇది ఆశ్చర్యకరంగా సులభం (నా వైపు వెర్రి లోపాల వెలుపల). CSS వేరియబుల్స్కు మద్దతు ఇవ్వడానికి ఒక చిన్న రిఫ్యాక్టర్ ఉంది మరియు CSS అనుకూల లక్షణాలకు మద్దతు ఇవ్వని బ్రౌజర్ ఉంటే నాకు ఫాల్‌బ్యాక్ ఉందని నిర్ధారిస్తుంది, కానీ దాని గురించి. జెరెమీ చేసిన అదే పనిని నేను చాలా చక్కగా చేసాను.

Read More

Using Web Mentions in a static site (Hugo)

Paul Kinlan

నా బ్లాగ్ పూర్తిగా స్టాటిక్ సైట్, ఇది హ్యూగోతో నిర్మించబడింది మరియు జైట్ తో హోస్ట్ చేయబడింది. ఇది నాకు గొప్ప పరిష్కారం, ఒక సాధారణ బ్లాగులో చాలా సరళమైన విస్తరణ ప్రక్రియ ఉంది మరియు ఇది వేగంగా వేగంగా లోడ్ అవుతుంది. గణాంకపరంగా ఉత్పత్తి చేయబడిన సైట్‌లకు కొన్ని లోపాలు ఉన్నాయి, మీ పేజీలో విలీనం కావడానికి డైనమిక్ ఏదైనా మీకు అవసరమైనప్పుడు పెద్దది (ఉదాహరణకు వ్యాఖ్యలు). డైనమిక్ కంటెంట్‌ను సులభంగా హోస్ట్ చేయలేకపోవడం అంటే మీరు 3 వ పార్టీ జావాస్క్రిప్ట్‌పై ఆధారపడటం అంటే మీ పేజీకి పూర్తి ప్రాప్యత లభిస్తుంది మరియు అది ఏమి చేస్తుందో మీకు తెలియదు - ఇది మీ వినియోగదారులను ట్రాక్ చేయడం లేదా మీ పేజీని మందగించడం లోడ్.

Read More

Creating a pop-out iframe with adoptNode and "magic iframes"

Paul Kinlan

నవీకరణ: అక్టోబర్ 8 - ఈ ### ముఖ్యమైన సమస్యలు. నేను ఈ పోస్ట్ గురించి Jake Archibald తో పట్టుబడ్డాను, ఎందుకంటే నాకు ఏదో నవల ఉందని నేను అనుకున్నాను, సంభాషణ సమయంలో మేము ఈ పోస్ట్‌లో కొన్ని చెల్లనివిగా చేసే చాలా విషయాలను బయటపెట్టాము మరియు చాలా మంది డెవలపర్లు అని నేను అనుకోని ఈ ప్రక్రియలో నేను చాలా నేర్చుకున్నాను తెలుసు. .append() మరియు .appendChild() .append() .appendChild() స్వీకరిస్తుంది. ఇది ఈ సందర్భంలో adoptNode వాడకాన్ని నిరుపయోగంగా చేస్తుంది ఎందుకంటే అనుబంధ అల్గోరిథం నోడ్ స్వీకరించబడిందని నిర్ధారిస్తుంది. ఇది MDN డాక్స్‌లో పేర్కొనబడలేదు, కానీ spec .

Read More

Meatspace Augmented Reality: From Chester to Nagoya

Paul Kinlan

Some thoughts on AR after finding some during my travels. TL;DR - cheaper content creation and better discovery tools are needed.

Read More

Photos from Carlisle Castle

Paul Kinlan

నేను ఇటీవల అబ్బాయిలతో సెలవుదినం వెళ్ళాను మరియు మేము గత Carlisle Castle (ప్రపంచ జన్మస్థలం జేక్ ఆర్కిబాల్డ్ Carlisle Castle ). ఇది మేము UK లో ఉన్న మంచి కోటలలో ఒకటి మరియు మీరు ఈ ప్రాంతంలో ఉంటే సందర్శించడానికి కొంత సమయం కేటాయించాలని నేను హృదయపూర్వకంగా సిఫార్సు చేస్తున్నాను. ఇంగ్లాండ్ మరియు స్కాట్లాండ్ చరిత్రలో కార్లిస్లే కాజిల్ పోషించిన పాత్ర ఎంత ముఖ్యమైనదో నేను చేయలేదు, మరియు మేము అక్కడ ఉన్నప్పుడే మరింత తెలుసుకోవడం చాలా బాగుంది. స్కాట్లాండ్ నుండి తిరిగి వచ్చిన తరువాత, స్కాట్లాండ్‌తో మా భవిష్యత్ సంబంధాలపై బ్రెక్సిట్ కలిగివుండే సంభావ్య ప్రభావాన్ని ప్రతిబింబించే అవకాశం నాకు లభించింది మరియు కార్లిస్లే ఎంత దగ్గరగా ఉందో, స్వాతంత్ర్యం కోసం పునరుద్ధరించిన పుష్ ఉంటే ఏమి జరుగుతుందో ఎవరికి తెలుసు.

Read More

Idle observation: Indexing text in images

Paul Kinlan

నేను ఇతర రోజు లాంగోలెన్‌లోని అబ్బాయిలతో కలిసి ఉన్నాను (ఇది ఒక అందమైన పట్టణం) మరియు నేను ఈ ప్రాంత చరిత్రను కలిగి ఉన్న సమాచార సంకేతాల చిత్రాలను తీస్తున్నాను, తద్వారా నేను తరువాత చదవగలను, మరియు నేను చూస్తానని అనుకున్నాను సంకేతం దాటి నడుస్తున్న వ్యక్తుల కంటే సమాచారం అందుబాటులో ఉందో లేదో చూడటానికి వెబ్ - మరియు అది కాదు. నేను అప్పుడు కరపత్రాల గురించి ఆలోచిస్తున్నాను, వాటిలోని కంటెంట్ వెబ్‌లో కనుగొనడం దాదాపు అసాధ్యం. చిత్రాలలోని వచనం గురించి చాలా మంది శ్రద్ధ వహిస్తారని మరియు వాటిని శోధించడానికి కష్టపడే సెర్చ్ ఇంజన్లు మరియు వినియోగదారులకు అందుబాటులో ఉంచడం నాకు ఖచ్చితంగా తెలియదు, కాని వెబ్‌లో ఎక్కువ కంటెంట్‌ను తీసుకురావడం మరియు సమాచారానికి ప్రాప్యతను మెరుగుపరచడం చాలా మంచి విజయం అనిపిస్తుంది.

Read More

Liverpool World Museum

Paul Kinlan

నేను ఇతర వారంలో పిల్లలను లివర్‌పూల్ వరల్డ్ హిస్టరీ మ్యూజియానికి తీసుకువెళ్ళాను, ఇది చాలా చక్కగా ఉంది. సుమారు 30 సంవత్సరాలలో స్పేస్ అండ్ టైమ్ విభాగం మారలేదు, బగ్ ఎన్‌క్లోజర్ యొక్క పెద్ద విభాగం మూసివేయబడింది మరియు అక్వేరియం నాకు గుర్తున్న దానికంటే చిన్నదిగా అనిపించింది. ఈజిప్టు విభాగం తెరిచి ఉంది (నేను చివరిసారిగా వెళ్ళినప్పుడు కాదు) మరియు ఇది చాలా అద్భుతంగా ఉంది.

Read More

Bookstore - Llangollen

Paul Kinlan

నేను ఈ స్థలాన్ని ప్రేమిస్తున్నాను, ఇది లాంగోలెన్‌లోని ఒక కేఫ్ పైన ఉంది. నేను దాదాపు 30 సంవత్సరాల క్రితం నా తాతామామలతో ఇక్కడకు వచ్చాను మరియు ఇప్పుడు చాలా చక్కనిది. నా ఏకైక కోరిక ఏమిటంటే ఇంకా ఎక్కువ కామిక్స్ పుస్తకాలు ఉన్నాయి - నేను చిన్నతనంలో ఎక్కువ కుప్ప ఉందని ప్రమాణం చేస్తున్నాను. Check it out

Read More

Webmention.app

Paul Kinlan

నేను Webmentions ఆలోచనను ప్రేమిస్తున్నాను, అయినప్పటికీ నా సైట్‌లో దీన్ని అమలు చేయడానికి నాకు సమయం లేదు. ఉన్నత-స్థాయి వెబ్‌లో వెబ్‌లోని ఇతర కంటెంట్‌కు వ్యాఖ్యానించడానికి, ఇష్టపడటానికి మరియు ప్రత్యుత్తరం ఇవ్వడానికి మిమ్మల్ని అనుమతిస్తుంది మరియు డిస్కుస్ (నా సైట్ నుండి తొలగించడానికి నేను ఆసక్తిగా ఉన్నాను) వంటి సాధనాలతో కేంద్రీకృతమై లేకుండా ఆ కంటెంట్‌కు ఇది కనిపిస్తుంది.

వెబ్ ప్రస్తావనలు పంపినవారు మరియు రిసీవర్ అనే రెండు భాగాలుగా విభజించబడ్డాయి. రిసీవర్ అనేది నేను ఒక పోస్ట్ వ్రాస్తున్న సైట్ మరియు వారి బ్లాగుకు ఇన్‌బౌండ్ లింకులు లేదా ప్రతిచర్యలను చూపించే వారి సైట్‌లో ఏదైనా ఉండవచ్చు; మరియు పంపినవారు నాకు బాగానే ఉన్నారు. నేను వ్రాసిన లేదా వారు సృష్టించిన కొంత కంటెంట్‌కు ప్రతిస్పందించిన రిమోట్ సైట్‌ను నేను అనుమతించాలి.

సమస్య యొక్క ఒక భాగాన్ని పరిష్కరించడానికి బదులుగా Remy Sharp webmention.app ను సృష్టించింది: పింగ్‌లను పంపడం. రెమి యొక్క సాధనం కేవలం CLI స్క్రిప్ట్‌కు కాల్ చేయడం ద్వారా నేను లింక్ చేసిన సంభావ్య రిసీవర్‌లకు 'పింగ్స్' పంపడం సులభం చేస్తుంది.

నేను హ్యూగో మరియు స్టాటిక్-బిల్డర్ సాధనాన్ని ఉపయోగించి జైట్ ఉపయోగించి నా బ్లాగును హోస్ట్ చేస్తాను, కాబట్టి ఇది relatively trivial for me to add in support for webmention app . నేను npm i webmention చేసి, ఆపై నా build.sh ఫైల్ నుండి సాధనం యొక్క CLI సంస్కరణను పిలుస్తాను - ఇది నిజంగా చాలా సులభం.

ఇప్పుడు నేను ఒక పోస్ట్‌ను సృష్టించినప్పుడు, నేను వారి సైట్ గురించి కొంత కంటెంట్‌ను సృష్టించిన అన్ని క్రొత్త URL లకు శీఘ్ర పింగ్ పంపాలి.

Creating a commit with multiple files to Github with JS on the web

Paul Kinlan

నా సైట్ entirely static . ఇది Hugo తో నిర్మించబడింది మరియు Hugo తో హోస్ట్ Zeit . సెటప్‌తో నేను చాలా సంతోషంగా ఉన్నాను, నేను తక్షణ నిర్మాణాలు మరియు సూపర్ ఫాస్ట్ సిడిఎన్డ్ కంటెంట్ డెలివరీకి దగ్గరవుతాను మరియు నేను అవసరమైన అన్ని పనులను చేయగలను ఎందుకంటే నేను ఏ రాష్ట్రాన్ని నిర్వహించాల్సిన అవసరం లేదు. నేను ఈ సైట్ కోసం ఒక simple UI సృష్టించాను మరియు నా podcast creator కూడా నా స్థిరంగా హోస్ట్ చేసిన సైట్‌కు క్రొత్త కంటెంట్‌ను త్వరగా పోస్ట్ చేయడానికి వీలు కల్పిస్తుంది. So. నేను ఎలా చేసాను?

Read More

Screen Recorder: recording microphone and the desktop audio at the same time

Paul Kinlan

ప్రపంచంలోని సరళమైన స్క్రీన్ రికార్డింగ్ సాఫ్ట్‌వేర్‌ను నిర్మించాలనే లక్ష్యం నాకు ఉంది మరియు గత రెండు నెలలుగా నేను ఈ ప్రాజెక్టుపై నెమ్మదిగా నూడుల్ చేస్తున్నాను (నా ఉద్దేశ్యం నిజంగా నెమ్మదిగా).

మునుపటి పోస్ట్‌లలో, అన్ని ఇన్‌పుట్ మూలాల నుండి ప్రసారాలతో screen recording and a voice overlay ద్వారా నేను screen recording and a voice overlay ను పొందాను. నిరాశకు గురైన ఒక ప్రాంతం ఏమిటంటే, డెస్క్‌టాప్ నుండి ఆడియోను ఎలా పొందాలో నేను పని చేయలేకపోయాను * మరియు * స్పీకర్ నుండి ఆడియోను అతివ్యాప్తి చేయండి. చివరకు దీన్ని ఎలా చేయాలో నేను పనిచేశాను.

మొదట, Chrome లోని getDisplayMedia ఇప్పుడు ఆడియో సంగ్రహాన్ని అనుమతిస్తుంది, getDisplayMedia బేసి పర్యవేక్షణ ఉన్నట్లు అనిపిస్తుంది, దీనిలో ఫంక్షన్ కాల్‌లో audio: true ని పేర్కొనడానికి ఇది మిమ్మల్ని అనుమతించలేదు, ఇప్పుడు మీరు చేయవచ్చు.

const audio = audioToggle.checked || false;
desktopStream = await navigator.mediaDevices.getDisplayMedia({ video:true, audio: audio });

రెండవది, ఆడియో స్ట్రీమ్‌లో రెండు ట్రాక్‌లను సృష్టించడం ద్వారా నేను కోరుకున్నదాన్ని పొందగలుగుతాను అని నేను MediaRecorder అనుకున్నాను, అయితే Chrome యొక్క MediaRecorder API ఒక ట్రాక్‌ను మాత్రమే అవుట్పుట్ MediaRecorder నేను తెలుసుకున్నాను, మరియు 2 వ, ఇది ఏమైనప్పటికీ MediaRecorder ఎందుకంటే ట్రాక్‌లు DVD మ్యూటిపుల్ ఆడియో ట్రాక్‌ల మాదిరిగా ఒకే సమయంలో ఒకరు మాత్రమే ప్లే చేయగలరు.

పరిష్కారం చాలా మందికి చాలా సులభం, కానీ ఇది నాకు క్రొత్తది: వెబ్ ఆడియోని ఉపయోగించండి.

వెబ్‌ఆడియో API కి createMediaStreamSource మరియు createMediaStreamDestination createMediaStreamSource createMediaStreamDestination , ఈ రెండూ సమస్యను పరిష్కరించడానికి API అవసరం. createMediaStreamSource నా డెస్క్‌టాప్ ఆడియో మరియు మైక్రోఫోన్ నుండి స్ట్రీమ్‌లను తీసుకోవచ్చు మరియు రెండింటినీ createMediaStreamDestination సృష్టించిన ఆబ్జెక్ట్‌తో అనుసంధానించడం ద్వారా ఈ ఒక స్ట్రీమ్‌ను MediaRecorder API లోకి పైప్ చేసే సామర్థ్యాన్ని ఇస్తుంది.

const mergeAudioStreams = (desktopStream, voiceStream) => {
  const context = new AudioContext();
    
  // Create a couple of sources
  const source1 = context.createMediaStreamSource(desktopStream);
  const source2 = context.createMediaStreamSource(voiceStream);
  const destination = context.createMediaStreamDestination();
  
  const desktopGain = context.createGain();
  const voiceGain = context.createGain();
    
  desktopGain.gain.value = 0.7;
  voiceGain.gain.value = 0.7;
   
  source1.connect(desktopGain).connect(destination);
  // Connect source2
  source2.connect(voiceGain).connect(destination);
    
  return destination.stream.getAudioTracks();
};

సాధారణ.

పూర్తి కోడ్‌ను my glitch చూడవచ్చు మరియు డెమోను ఇక్కడ చూడవచ్చు: https://screen-record-voice.glitch.me/

{{<ఫాస్ట్-యూట్యూబ్ oGIdqcMFKlA>}}

Extracting text from an image: Experiments with Shape Detection

Paul Kinlan

గూగుల్ IO తర్వాత నాకు కొంచెం సమయం ఉంది మరియు నేను కలిగి ఉన్న దీర్ఘకాలిక దురదను గీయాలని అనుకున్నాను. బ్రౌజర్‌లోని చిత్రాల లోపల ఉన్న వచనాన్ని కాపీ చేయగలుగుతున్నాను. అంతే. ఇది ప్రతి ఒక్కరికీ చక్కని లక్షణంగా ఉంటుందని నేను భావిస్తున్నాను.

కార్యాచరణను నేరుగా Chrome లోకి జోడించడం అంత సులభం కాదు, కానీ నేను Android లోని ఉద్దేశ్య వ్యవస్థను సద్వినియోగం చేసుకోగలనని నాకు తెలుసు మరియు నేను ఇప్పుడు వెబ్‌తో (లేదా Android లో కనీసం Chrome) దీన్ని చేయగలను.

వెబ్ ప్లాట్‌ఫారమ్‌కు రెండు కొత్త చేర్పులు - షేర్ టార్గెట్ స్థాయి 2 (లేదా నేను దానిని ఫైల్ షేర్ అని TextDetector ) మరియు షేప్ డిటెక్షన్ API - have allowed me to build a utility that I can Share images to and get the text held inside them .

ప్రాథమిక అమలు సాపేక్షంగా సూటిగా ముందుకు ఉంటుంది, మీరు సేవా వర్కర్‌లో షేర్ టార్గెట్ మరియు హ్యాండ్లర్‌ను సృష్టిస్తారు, ఆపై వినియోగదారు పంచుకున్న చిత్రం మీకు TextDetector మీరు దానిపై TextDetector ను అమలు చేస్తారు.

Share Target API మీ వెబ్ అప్లికేషన్‌ను స్థానిక షేరింగ్ ఉప వ్యవస్థలో భాగం Share Target API అనుమతిస్తుంది, మరియు ఈ సందర్భంలో మీరు మీ Web App Manifest ఈ క్రింది విధంగా ప్రకటించడం ద్వారా అన్ని image/* రకాలను నిర్వహించడానికి నమోదు చేసుకోవచ్చు.

"share_target": {
  "action": "/index.html",
  "method": "POST",
  "enctype": "multipart/form-data",
  "params": {
    "files": [
      {
        "name": "file",
        "accept": ["image/*"]
      }
    ]
  }
}

మీ PWA వ్యవస్థాపించబడినప్పుడు, మీరు చిత్రాలను పంచుకునే అన్ని ప్రదేశాలలో ఈ క్రింది విధంగా చూస్తారు:

Share Target API ఫైల్‌లను ఫారమ్ పోస్ట్ లాగా భాగస్వామ్యం చేస్తుంది. ఫైల్ వెబ్ అనువర్తనానికి భాగస్వామ్యం చేయబడినప్పుడు, సేవా కార్మికుడు సక్రియం చేయబడితే, fetch హ్యాండ్లర్ ఫైల్ డేటాతో ప్రారంభించబడుతుంది. డేటా ఇప్పుడు సర్వీస్ వర్కర్ లోపల ఉంది, కానీ ప్రస్తుత విండోలో నాకు ఇది అవసరం, తద్వారా నేను దీన్ని ప్రాసెస్ చేయగలను, ఏ విండో అభ్యర్థనను ప్రవేశపెట్టిందో సేవకు తెలుసు, కాబట్టి మీరు క్లయింట్‌ను సులభంగా లక్ష్యంగా చేసుకొని డేటాను పంపవచ్చు.

self.addEventListener('fetch', event => {
  if (event.request.method === 'POST') {
    event.respondWith(Response.redirect('/index.html'));
    event.waitUntil(async function () {
      const data = await event.request.formData();
      const client = await self.clients.get(event.resultingClientId || event.clientId);
      const file = data.get('file');
      client.postMessage({ file, action: 'load-image' });
    }());
    
    return;
  }
  ...
  ...
}

చిత్రం వినియోగదారు ఇంటర్‌ఫేస్‌లో ఉన్నప్పుడు, నేను దానిని టెక్స్ట్ డిటెక్షన్ API తో ప్రాసెస్ చేస్తాను.

navigator.serviceWorker.onmessage = (event) => {  
  const file = event.data.file;
  const imgEl = document.getElementById('img');
  const outputEl = document.getElementById('output');
  const objUrl = URL.createObjectURL(file);
  imgEl.src = objUrl;
  imgEl.onload = () => {
    const texts = await textDetector.detect(imgEl);
    texts.forEach(text => {
      const textEl = document.createElement('p');
      textEl.textContent = text.rawValue;
      outputEl.appendChild(textEl);
    });
  };
  ...
};

అతిపెద్ద సమస్య ఏమిటంటే బ్రౌజర్ సహజంగా చిత్రాన్ని తిప్పడం లేదు (మీరు క్రింద చూడగలిగినట్లు), మరియు ఆకృతి గుర్తింపు API కి సరైన పఠన ధోరణిలో ఉండటానికి టెక్స్ట్ అవసరం.

భ్రమణాన్ని గుర్తించడానికి నేను EXIF-Js library ను ఉపయోగించడం చాలా సులభం, ఆపై చిత్రాన్ని తిరిగి EXIF-Js library చేయడానికి కొన్ని ప్రాథమిక కాన్వాస్ మానిప్యులేషన్ EXIF-Js library .

EXIF.getData(imgEl, async function() {
  // http://sylvana.net/jpegcrop/exif_orientation.html
  const orientation = EXIF.getTag(this, 'Orientation');
  const [width, height] = (orientation > 4) 
                  ? [ imgEl.naturalWidth, imgEl.naturalHeight ]
                  : [ imgEl.naturalHeight, imgEl.naturalWidth ];

  canvas.width = width;
  canvas.height = height;
  const context = canvas.getContext('2d');
  // We have to get the correct orientation for the image
  // See also https://stackoverflow.com/questions/20600800/js-client-side-exif-orientation-rotate-and-mirror-jpeg-images
  switch(orientation) {
    case 2: context.transform(-1, 0, 0, 1, width, 0); break;
    case 3: context.transform(-1, 0, 0, -1, width, height); break;
    case 4: context.transform(1, 0, 0, -1, 0, height); break;
    case 5: context.transform(0, 1, 1, 0, 0, 0); break;
    case 6: context.transform(0, 1, -1, 0, height, 0); break;
    case 7: context.transform(0, -1, -1, 0, height, width); break;
    case 8: context.transform(0, -1, 1, 0, 0, width); break;
  }
  context.drawImage(imgEl, 0, 0);
}

మరియు వోయిలా, మీరు అనువర్తనానికి ఒక చిత్రాన్ని భాగస్వామ్యం చేస్తే అది చిత్రాన్ని తిప్పేస్తుంది మరియు అది కనుగొన్న టెక్స్ట్ యొక్క అవుట్పుట్ను తిరిగి ఇస్తుంది.

ఈ చిన్న ప్రయోగాన్ని సృష్టించడం చాలా సరదాగా ఉంది మరియు ఇది నాకు వెంటనే ఉపయోగపడింది. అయితే, ఇది inconsistency of the web platform హైలైట్ చేస్తుంది. ఈ API లు అన్ని బ్రౌజర్‌లలో అందుబాటులో లేవు, అవి Chrome యొక్క అన్ని వెర్షన్లలో కూడా అందుబాటులో లేవు - దీని అర్థం నేను ఈ కథనాన్ని Chrome OS వ్రాసేటప్పుడు, నేను అనువర్తనాన్ని ఉపయోగించలేను, కానీ అదే సమయంలో, నేను ఉపయోగించినప్పుడు … OMG, చాలా బాగుంది.

Wood Carving found in Engakuji Shrine near Kamakura

Sakura

Paul Kinlan

నేను మరింత ప్రత్యేకంగా ఈ 'Yaezakura'

Read More