分类目录归档:后端开发技术&PHP

让FPM以root用户运行

fpm默认是不能以root用户运行的,会报:
ERROR: [pool www] please specify user and group other than root

如果有特殊原因,需要以root用户运行,需要修改配置,以让fpm支持以root用户的方式运行fpm
vim /lib/systemd/system/php-fpm.service
把:
ExecStart=/usr/sbin/php-fpm –nodaemonize
修改成:
ExecStart=/usr/sbin/php-fpm -R –nodaemonize

改完后,需要执行:
systemctl daemon-reload
以生效修改

再执行,重启fpm进程
systemctl restart php-fpm

如果之前的fpm是手动运行的,需要以发送Linux信号的方式停止fpm服务,如果开启的fpm进程较多,要多等一会儿,等子进程完了再systemctl start php-fpm,不然会出现端口被占用,无法启动的情况
kill -SIGKILL [fpm master的进程号]

正则手记

这几个老是容易忘记

  • 在多个字符串中选择一个字符串匹配
    111(?:abc|def)222
  • 只匹配hello php和java中的hello, 不匹配hello python中的hello
    hello (?=php|java)
  • 只匹配除 hello python和javascript外的其它串中的hello
    hello (?!python|javascript)
  • 只匹配dan或john is a good man中的is a good man
    (?<=dan|john) is a good man
  • 只匹配除dan和john以外中的is a good man
    (?<!dan|john) is a good man 

 

CURL报”426 Unsupported SSL protocol TLSv1.2″时,升级curl, openssl, php-curl

服务器上php 5.6调用curl时,返回”426 Unsupported SSL protocol TLSv1.2, Upgrade to TLSv1.3 is required”.

用”openssl ciphers -V | column -t“ 查看,原来是openssl不支持TLSv1.3,需要升级,但由于PHP的CURL扩展是调用的Curl,Curl再调用的openssl,所以需要把openssl和curl升级,把php-curl重新编译.

思路是重新安装openssl和curl到新目录,以防止破坏以前的依赖,不然就容易翻车。

一、升级openssl

去https://www.openssl.org/source/下载v1版本,因为我是php5,系统也比较老,下载v1保险一些。
./config –prefix=/usr/local/openssl
make
make install

完成后测试下: /usr/local/openssl/bin/openssl version,
可能会报错:
bin/openssl: error while loading shared libraries: libssl.so.1.1: cannot open shared object file: No such file or directory
建立软链
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/lib64/libssl.so.1.1
ln -s /usr/local/openssl/lib/libcrypto.so.1.1 /usr/lib64/libcrypto.so.1.1

二、升级CURL

去官网下载最新的curl,按标准安装方法,把curl安装到/usr/local/curl目录,需要指定上面新的openssl目录
./configure –prefix=/usr/local/curl –with-ssl=/usr/local/openssl

完成后可以测试一下,是否可以下载TLSv1.3的URL内容,如果没有问题就到三步

三、重新编译php-curl

去PHP官网下载和你当前版本一样的原码,解压,注意要指定新的curl目录
/root/software/php-5.6.40/ext/curl
phpize
./configure –with-curl=/usr/local/curl/
make
make install

如果是php8的curl扩展到这一步要报错:

checking for cURL support… yes, shared
checking for libcurl >= 7.29.0… no
configure: error: Package requirements (libcurl >= 7.29.0) were not met:

No package ‘libcurl’ found

Consider adjusting the PKG_CONFIG_PATH environment variable if you
installed software in a non-standard prefix.

Alternatively, you may set the environment variables CURL_CFLAGS
and CURL_LIBS to avoid the need to call pkg-config.
See the pkg-config man page for more details.

要这样才可以
export PKG_CONFIG_PATH=/usr/local/curl/lib/pkgconfig

报下面的错误的话要这样:
libtool: compile: cc -I. -I/root/software/php-8.3.1/ext/curl -I/root/software/php-8.3.1/ext/curl/include -I/root/software/php-8.3.1/ext/curl/main -I/root/software/php-8.3.1/ext/curl-I/usr/include/php -I/usr/include/php/main -I/usr/include/php/TSRM -I/usr/include/php/Zend -I/usr/include/php/ext -I/usr/include/php/ext/date/lib -I/usr/local/curl/include/ -DHAVE_CONFIG_H -g -O2 -D_GNU_SOURCE -DZEND_COMPILE_DL_EXT=1 -c /root/software/php-8.3.1/ext/curl/interface.c -MMD -MF interface.dep -MT interface.lo -fPIC -DPIC -o .libs/interface.o
/root/software/php-8.3.1/ext/curl/interface.c:58:28: fatal error: zend_smart_str.h: No such file or directory
./configure –with-curl=/usr/local/curl –with-php-config=/opt/remi/php83/root/bin/php-config

报下面的错误的话要这样make:
/root/software/php-8.3.1/ext/curl/multi.c: In function ‘curl_multi_get_gc’:
/root/software/php-8.3.1/ext/curl/multi.c:572:2: error: ‘for’ loop initial declarations are only allowed in C99 mode

或者修改代码,把那一行的行内定义提出去,或者用下面的命令编译:
make CFLAGS=-std=c99

最后测试一下:
php -r “phpinfo();” | grep cURL
输出
cURL support => enabled
cURL Information => 8.2.1

没有问题,如果是fpm,要重启fpm。

其它的问题
如果在编译的时候出现很多语法错误,有可能是系统安装了多个php版本,引用到了错误的php头文件,在.configure的时候,要指定–with-php-config
安装好扩展之后,但加载扩展如果出现下面的错误,是因为php扩展和curl的版本不对,需要下载新的curl版本重新安装。
PHP Warning: PHP Startup: Unable to load dynamic library ‘curl’ (tried: /opt/remi/php83/root/usr/lib64/php/modules/curl (/opt/remi/php83/root/usr/lib64/php/modules/curl: cannot openshared object file: No such file or directory), /opt/remi/php83/root/usr/lib64/php/modules/curl.so (/opt/remi/php83/root/usr/lib64/php/modules/curl.so: undefined symbol: curl_easy_escape)) in Unknown on line 0

MySQL大表改结构(pt-online-schema-change)

yum install -y https://repo.percona.com/yum/percona-release-latest.noarch.rpm

yum install percona-toolkit

https://www.percona.com/doc/percona-toolkit/LATEST/pt-online-schema-change.html

pt-online-schema-change –user=xxx –password=”xxx” –host=”xxx” –alter=”ADD bbb INT NULL DEFAULT ‘0’” D=dmp_main,t=test –execute

PHP防止重复运行代码

/**
 * 获取当前程序运行了多少个进程
 * @param $processName 程序进程名,要唯一
 */
function GetInstancePids($processName)
{
    // 把文件放到外面去,防止发布版本把状态文件搞没了
    $dir = dirname(dirname(dirname(dirname(__FILE__)))).'/data'.'/pids';
    $file = $dir . DIRECTORY_SEPARATOR . $processName;
    $pinfo = getCurrentProcessInfo();

    if (!file_exists($file)) {
        file_put_contents($file, "{$pinfo['pid']}\t{$pinfo['cmd']}\n");
        return true;
    }

    $i = 0;
    $pidfile = fopen($file, 'r+');
    do {
        if (flock($pidfile, LOCK_EX)) {
            break;
        } else {
            if ($i++ == 10) {
                exit('try 10 times to lock pid file,faild');
            }
            usleep(1000);
        }
    } while (true);

    $read = fread($pidfile, 10240);
    rewind($pidfile);
    $read = explode("\n", trim($read));
    $process_info = [];
    foreach ($read as $index => $line) {
        list($pid, $cmd) = explode("\t", $line);
        if (!empty($pid) && isPidExists($pid, $cmd)) {
            $process_info[] = "{$pid}\t{$cmd}";
        }
    }
    
    $process_info[] = "{$pinfo['pid']}\t{$pinfo['cmd']}";
    ftruncate($pidfile,0);
    fwrite($pidfile, implode("\n", $process_info));
    fflush($pidfile);
    flock($pidfile, LOCK_UN);
    fclose($pidfile);

    return true;
}

/**
 * 返回自身进程信息
 */
function getCurrentProcessInfo()
{
    $mypid = getmypid();
    $outputs = [];
    exec('ps -ax | grep -E "^\s*' . $mypid . '\s+"', $outputs);
    $matched = [];
    preg_match('/^\s*(\S+?)\s+?\S+?\s+?(\S+?)\s+?\S+?\s+?(.+)/', $outputs[0], $matched);
    return [
        'pid' => $matched[1],
        'uptime' => $matched[2],
        'cmd' => $matched[3],
    ];
}

function isPidExists($pid, $cmd)
{
    exec('ps -ax | grep -E "^\s?'. $pid . '.+?'.$cmd.'"', $result);
    return isset($result[0]);
}

 

使用的时候:

$pids = GetInstancePids(“xxx”);
if (count($pids) > 1) die(“程序运行中”);

写一个Composer包的Composer.json模板

目录结构

{
    "name": "myjoyoo/affiliate-sdk",
    "description": "如LinkShare、CJ、PJ、Awin之类的联盟的SDK接口封装",
    "type": "l",
    "require": {
        "php": ">=8.0",
        "guzzlehttp/guzzle": "^7.3",
        "nesbot/carbon": "^2.48"
    },
    "license": "Apache",
    "authors": [
        {
            "name": "myjoyoo",
            "email": "[email protected]"
        }
    ],
    "minimum-stability": "dev",
    "autoload": {
        "psr-4": {
            "AffiliateSDK\\": "src"
        },
        "files": ["src/include/commonFunction.php"]
    }
}

改了之后,需要执行下面的命令去生效
composer dump-auotload

PHP Carbon时区操作

在没有指定时区的时候,系统是以date_default_timezone_get 获取到的时区在进行转换。
如果我们要为某个时间单独指定时区的话,可以按以下的方式。

// 没有指定时间前
var_dump(Carbon::parse('now')->toDateTimeString());

// 实例化一个时区对象
$tz = new CarbonTimeZone('+08:00');
// 在解析的时候,把时区带上
var_dump(Carbon::parse('now', $tz)->toDateTimeString());

 

PHP在进程相关的笔记

exec和pcntl_exec的区别

echo "开始执行\n";
pcntl_exec('/usr/bin/php', ['-r', 'sleep(10);']);

// 等待10秒后,程序结束
// 这行代码不会被执行
echo "PHP代码结束\n";

exec是在当前进程里新开了一个进程,并等待新进程执行完后再接着执行,新开进程的进程号和当前进程号不同。

pcntl_exec不新开进程,在当前进程接着执行,pcntl_exec后面的php代码不再被执行,接收不到输出。

进程信号处理

常用信号:

代码 数值 说明 操作
HUP 1 通常是重启、加载配置文件
INT 2 终端中断 Ctrl – C
QUIT 3 终端退出 Ctro – \
KILL 9 强制中断,信息不能被捕获
ALRM 14 警告
TERM 15 终止运行,会生成dump?
CONT 18 恢复执行
STOP 19 暂停执行
<?php
declare(ticks = 1);
$run = true;

function signal_handler($signal) {
    global $run;
    print "Caught SIGALRM: {$signal}\n";

    switch ($signal) {
        case SIGHUP:
            # 重新加载
            break;

        case SIGINT:
        case SIGQUIT:
            $run = false;
            break;
        
        default:
            # code...
            break;
    }
}

pcntl_signal(SIGHUP, "signal_handler");
pcntl_signal(SIGINT, "signal_handler");
pcntl_signal(SIGQUIT, "signal_handler");

while ($run) {
    sleep(1);
}

echo "end.";

注意啊,这东西不能在VS Code的控制台下运行,不然中断回调函数不会被执行。

 

获取YouTube的博主和视频信息

有3种报表:
1、通过DataApi,这种方式相对较直接,通过调用api获取数据,也可以操作数据(需要登录验证)2、Analytics API:这个报表是实时获取。
3、Reporting API:这个是生成报表数据再异步下载的,可以批量生成,如果数据量很大的话,建议用这个。

现在我们用的是第一种方式。

打开:https://console.cloud.google.com/,建立项目。
“API和服务“里,开通”库“里的”YouTube Data API v3”
开通后会得到token,后面会需要。

在这里可以查看文档,可以方便的用他们提供的api tools进行测试。
https://developers.google.com/youtube/v3/docs

有一个比较坑人的地方是,打开测试Widget后,下面的用OAuth 2.0是默认开启的,如下图:

当把这个取消后,右边生成的代码不会改变,要在上面手动改一个参数后,才会变。
要注意这个问题,不然代码是有问题的,始终会按OAuth 2.0的方式生成。

PHP的使用教程在这里:
https://developers.google.com/youtube/v3/quickstart/php

获取博主信息

请求:
GET https://youtube.googleapis.com/youtube/v3/channels?part=snippet%2CcontentDetails%2Cstatistics&forUsername=GoogleDevelopers&key=[YOUR_API_KEY] HTTP/1.1

Authorization: Bearer [YOUR_ACCESS_TOKEN]
Accept: application/json

返回:
{
  "kind": "youtube#channelListResponse",
  "etag": "LdG9BNUGur4iY7vuvSdW3_7PNP8",
  "pageInfo": {
    "totalResults": 1,
    "resultsPerPage": 5
  },
  "items": [
    {
      "kind": "youtube#channel",
      "etag": "6MkQzgqGne9K0Ol8mcuIHT0K8HQ",
      "id": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
      "snippet": {
        "title": "Google Developers",
        "description": "The Google Developers channel features talks from events, educational series, best practices, tips, and the latest updates across our products and platforms.\n\nSubscribe to Google Developers → https://goo.gle/developers\n",
        "customUrl": "googledevelopers",
        "publishedAt": "2007-08-23T00:34:43Z",
        "thumbnails": {
          "default": {
            "url": "https://yt3.ggpht.com/ytc/AAUvwngOju7AKiAvKEs1wtsZN366tyNPyMq3nD8eFkMF7bE=s88-c-k-c0x00ffffff-no-rj",
            "width": 88,
            "height": 88
          },
          "medium": {
            "url": "https://yt3.ggpht.com/ytc/AAUvwngOju7AKiAvKEs1wtsZN366tyNPyMq3nD8eFkMF7bE=s240-c-k-c0x00ffffff-no-rj",
            "width": 240,
            "height": 240
          },
          "high": {
            "url": "https://yt3.ggpht.com/ytc/AAUvwngOju7AKiAvKEs1wtsZN366tyNPyMq3nD8eFkMF7bE=s800-c-k-c0x00ffffff-no-rj",
            "width": 800,
            "height": 800
          }
        },
        "localized": {
          "title": "Google Developers",
          "description": "The Google Developers channel features talks from events, educational series, best practices, tips, and the latest updates across our products and platforms.\n\nSubscribe to Google Developers → https://goo.gle/developers\n"
        },
        "country": "US"
      },
      "contentDetails": {
        "relatedPlaylists": {
          "likes": "",
          "favorites": "",
          "uploads": "UU_x5XG1OV2P6uZZ5FSM9Ttw"
        }
      },
      "statistics": {
        "viewCount": "182712151",
        "subscriberCount": "2160000",
        "hiddenSubscriberCount": false,
        "videoCount": "5340"
      }
    }
  ]
}

 

根据用户获取视频列表,分页的时候需要注意传pageTaken参数进去,该值是该API上一次返回的,如果不传的话,是第一页。

发送:
List编号是上一个接口返回的UU开始的那个
GET https://youtube.googleapis.com/youtube/v3/playlistItems?part=contentDetails%2Csnippet%2Cstatus&playlistId=[List编号]&key=[YOUR_API_KEY] HTTP/1.1

Authorization: Bearer [YOUR_ACCESS_TOKEN]
Accept: application/json

返回:
{
  "kind": "youtube#playlistItemListResponse",
  "etag": "sKFBg0QAFkDAaRtysTrebMkkcN8",
  "nextPageToken": "CDIQAA",
  "items": [
    {
      "kind": "youtube#playlistItem",
      "etag": "n0z9esMo-NzLrFpY_pRAVr9dd7w",
      "id": "VVVfeDVYRzFPVjJQNnVaWjVGU005VHR3LlYtUXRjd0txOUpr",
      "snippet": {
        "publishedAt": "2021-05-13T20:17:27Z",
        "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
        "title": "Google I/O 2021, Android Studio 4.2, Google Play update, and more!",
        "description": "TL;DR 246 | The Google Developer News Show\n \n0:00 - Google I/O 2021 → https://goo.gle/3tKActE \n0:37 - Android Studio 4.2 → https://goo.gle/3hjinPQ  \n1:14 - New safety section in Google Play → https://goo.gle/3eH5rBB  \n1:46 - New Dashboard in Google Developer Profiles → https://goo.gle/33DWeDB  \n2:16 - Please remember to like, subscribe, and share! \n\nHere to bring you the latest developer news from across Google is Developer Advocate Meghan Metha. Tune in every week for a new episode, and let us know what you think of the latest announcements in the comments below! 😃\n\nFollow Google Developers on Instagram → https://goo.gle/googledevs             \n\nWatch more #DevShow → https://goo.gle/GDevShow               \nSubscribe to Google Developers → https://goo.gle/developers \n\n#Google #Developers",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/hqdefault.jpg",
            "width": 480,
            "height": 360
          },
          "standard": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/sddefault.jpg",
            "width": 640,
            "height": 480
          },
          "maxres": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/maxresdefault.jpg",
            "width": 1280,
            "height": 720
          }
        },
        "channelTitle": "Google Developers",
        "playlistId": "UU_x5XG1OV2P6uZZ5FSM9Ttw",
        "position": 0,
        "resourceId": {
          "kind": "youtube#video",
          "videoId": "V-QtcwKq9Jk"
        },
        "videoOwnerChannelTitle": "Google Developers",
        "videoOwnerChannelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw"
      },
      "contentDetails": {
        "videoId": "V-QtcwKq9Jk",
        "videoPublishedAt": "2021-05-13T21:00:21Z"
      },
      "status": {
        "privacyStatus": "public"
      }
    }
  ],
  "pageInfo": {
    "totalResults": 5340,
    "resultsPerPage": 50
  }
}

根据视频ID获取视频信息

请求:
GET https://youtube.googleapis.com/youtube/v3/videos?part=snippet%2CcontentDetails%2Cstatistics&id=Ks-_Mh1QhMc%2CV-QtcwKq9Jk&key=[YOUR_API_KEY] HTTP/1.1

Authorization: Bearer [YOUR_ACCESS_TOKEN]
Accept: application/json

id字段可以传以逗号分隔的多个id,该id是从上面的一个请求的返回的,contentDetails下的VideoId

返回:
{
  "kind": "youtube#videoListResponse",
  "etag": "zWPULojPN0SgmjLS7RzRh6217I4",
  "items": [
    {
      "kind": "youtube#video",
      "etag": "H0Be3-hhwR0AH_bFMPSsvwMkFhg",
      "id": "Ks-_Mh1QhMc",
      "snippet": {
        "publishedAt": "2012-10-01T15:27:35Z",
        "channelId": "UCAuUUnT6oDeKwE6v1NGQxug",
        "title": "Your body language may shape who you are | Amy Cuddy",
        "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/hqdefault.jpg",
            "width": 480,
            "height": 360
          },
          "standard": {
            "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/sddefault.jpg",
            "width": 640,
            "height": 480
          },
          "maxres": {
            "url": "https://i.ytimg.com/vi/Ks-_Mh1QhMc/maxresdefault.jpg",
            "width": 1280,
            "height": 720
          }
        },
        "channelTitle": "TED",
        "tags": [
          "Amy Cuddy",
          "TED",
          "TEDTalk",
          "TEDTalks",
          "TED Talk",
          "TED Talks",
          "TEDGlobal",
          "brain",
          "business",
          "psychology",
          "self",
          "success"
        ],
        "categoryId": "22",
        "liveBroadcastContent": "none",
        "defaultLanguage": "en",
        "localized": {
          "title": "Your body language may shape who you are | Amy Cuddy",
          "description": "Body language affects how others see us, but it may also change how we see ourselves. Social psychologist Amy Cuddy argues that \"power posing\" -- standing in a posture of confidence, even when we don't feel confident -- can boost feelings of confidence, and might have an impact on our chances for success. (Note: Some of the findings presented in this talk have been referenced in an ongoing debate among social scientists about robustness and reproducibility. Read Amy Cuddy's response here: http://ideas.ted.com/inside-the-debate-about-power-posing-a-q-a-with-amy-cuddy/)\n\nGet TED Talks recommended just for you! Learn more at https://www.ted.com/signup.\n\nThe TED Talks channel features the best talks and performances from the TED Conference, where the world's leading thinkers and doers give the talk of their lives in 18 minutes (or less). Look for talks on Technology, Entertainment and Design -- plus science, business, global issues, the arts and more.\n\nFollow TED on Twitter: http://www.twitter.com/TEDTalks\nLike TED on Facebook: https://www.facebook.com/TED\n\nSubscribe to our channel: https://www.youtube.com/TED"
        },
        "defaultAudioLanguage": "en"
      },
      "contentDetails": {
        "duration": "PT21M3S",
        "dimension": "2d",
        "definition": "hd",
        "caption": "true",
        "licensedContent": true,
        "contentRating": {},
        "projection": "rectangular"
      },
      "statistics": {
        "viewCount": "19630769",
        "likeCount": "293174",
        "dislikeCount": "5600",
        "favoriteCount": "0",
        "commentCount": "8671"
      }
    },
    {
      "kind": "youtube#video",
      "etag": "eLxJnVkjRvCXeqs4kfxlWfT5iSQ",
      "id": "V-QtcwKq9Jk",
      "snippet": {
        "publishedAt": "2021-05-13T21:00:21Z",
        "channelId": "UC_x5XG1OV2P6uZZ5FSM9Ttw",
        "title": "Google I/O 2021, Android Studio 4.2, Google Play update, and more!",
        "description": "TL;DR 246 | The Google Developer News Show\n \n0:00 - Google I/O 2021 → https://goo.gle/3tKActE \n0:37 - Android Studio 4.2 → https://goo.gle/3hjinPQ  \n1:14 - New safety section in Google Play → https://goo.gle/3eH5rBB  \n1:46 - New Dashboard in Google Developer Profiles → https://goo.gle/33DWeDB  \n2:16 - Please remember to like, subscribe, and share! \n\nHere to bring you the latest developer news from across Google is Developer Advocate Meghan Metha. Tune in every week for a new episode, and let us know what you think of the latest announcements in the comments below! 😃\n\nFollow Google Developers on Instagram → https://goo.gle/googledevs             \n\nWatch more #DevShow → https://goo.gle/GDevShow               \nSubscribe to Google Developers → https://goo.gle/developers \n\n#Google #Developers",
        "thumbnails": {
          "default": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/default.jpg",
            "width": 120,
            "height": 90
          },
          "medium": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/mqdefault.jpg",
            "width": 320,
            "height": 180
          },
          "high": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/hqdefault.jpg",
            "width": 480,
            "height": 360
          },
          "standard": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/sddefault.jpg",
            "width": 640,
            "height": 480
          },
          "maxres": {
            "url": "https://i.ytimg.com/vi/V-QtcwKq9Jk/maxresdefault.jpg",
            "width": 1280,
            "height": 720
          }
        },
        "channelTitle": "Google Developers",
        "tags": [
          "GDS: Yes",
          "google i/o",
          "google i/o 2021",
          "google i/o 21",
          "android studio 4.2",
          "google play",
          "google play update",
          "google play safety section",
          "google developer profiles",
          "google developer profiles dashboard",
          "android",
          "android developers",
          "google developer show",
          "the google developer show",
          "the developer show",
          "dev show",
          "dev news",
          "tl;dr",
          "developer news",
          "news",
          "updates",
          "ds",
          "google developers",
          "google news",
          "developers",
          "developer",
          "google latest",
          "google",
          "Meghan Metha"
        ],
        "categoryId": "28",
        "liveBroadcastContent": "none",
        "defaultLanguage": "en",
        "localized": {
          "title": "Google I/O 2021, Android Studio 4.2, Google Play update, and more!",
          "description": "TL;DR 246 | The Google Developer News Show\n \n0:00 - Google I/O 2021 → https://goo.gle/3tKActE \n0:37 - Android Studio 4.2 → https://goo.gle/3hjinPQ  \n1:14 - New safety section in Google Play → https://goo.gle/3eH5rBB  \n1:46 - New Dashboard in Google Developer Profiles → https://goo.gle/33DWeDB  \n2:16 - Please remember to like, subscribe, and share! \n\nHere to bring you the latest developer news from across Google is Developer Advocate Meghan Metha. Tune in every week for a new episode, and let us know what you think of the latest announcements in the comments below! 😃\n\nFollow Google Developers on Instagram → https://goo.gle/googledevs             \n\nWatch more #DevShow → https://goo.gle/GDevShow               \nSubscribe to Google Developers → https://goo.gle/developers \n\n#Google #Developers"
        },
        "defaultAudioLanguage": "en-US"
      },
      "contentDetails": {
        "duration": "PT2M33S",
        "dimension": "2d",
        "definition": "hd",
        "caption": "true",
        "licensedContent": false,
        "contentRating": {},
        "projection": "rectangular"
      },
      "statistics": {
        "viewCount": "6744",
        "likeCount": "301",
        "dislikeCount": "8",
        "favoriteCount": "0",
        "commentCount": "10"
      }
    }
  ],
  "pageInfo": {
    "totalResults": 2,
    "resultsPerPage": 2
  }
}