Twitterにアップされている動画のTSファイル一覧を表示&保存する

Twitterにアップされている動画で保存したい物があったので、HTTPリクエストログからURLをゲットしようとおもったら・・・
なんとm3u8の再生リスト形式になっていて動画自体も.tsに分割されていました。

#EXTM3U
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=320000,RESOLUTION=240x180,CODECS="mp4a.40.2,avc1.42001f"
/ext_tw_video/.../pu/pl/240x180/???.m3u8
#EXT-X-STREAM-INF:PROGRAM-ID=1,BANDWIDTH=832000,RESOLUTION=480x360,CODECS="mp4a.40.2,avc1.42001f"
/ext_tw_video/.../pu/pl/480x360/???.m3u8
#EXTM3U
#EXT-X-VERSION:6
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-TARGETDURATION:3
#EXTINF:3.000,
/ext_tw_video/.../pu/vid/0/3000/480x360/???.ts
#EXTINF:3.000,
/ext_tw_video/.../pu/vid/3000/6000/480x360/???.ts
#EXTINF:3.000,
/ext_tw_video/.../pu/vid/6000/9000/480x360/???.ts
#EXTINF:3.000,
/ext_tw_video/.../pu/vid/9000/12000/480x360/???.ts
#EXTINF:3.000,
/ext_tw_video/.../pu/vid/12000/15000/480x360/???.ts
....

再生リストから欲しいサイズの動画を選んで分割ファイルをダウンロードすれば良いんだろうけど面倒くさいw
それに、分割は3秒毎なので2分を超える動画は70ファイル超え!

そんなの1つずつURLをコピペなんてやってられない・・って事で、動画サイズ毎のURLとファイルを一覧表示するGreasemonkeyスクリプトを作ってみました。
動作してる動画はこちら。

1ファイル毎に手動保存なのはローカルに自動でファイルを保存するAPIが呼び出せないから。
userChrome.jsとして動かせばできるんだけど、セキュリティ的にあまり宜しくない。

まあ随分と楽になるんじゃないかなーと。
保存時にはINDEXに表示されている番号と同じファイル名にしないと、TSファイルの連結時に時系列がごちゃごちゃになりますw

おまけ?として法人など業界用の動画VMAP形式の動画も落とせるようにしました。
分割されていないので楽ちんですw
続きを読む

WordPressが生成したサムネイル画像からexif情報を削除する

WordPressで画像をアップロードするとサムネイル画像が生成されますよねー。
そのサムネイル生成方法はサーバー設定でImagickが有効化されているとImagickがGDが有効な場合はGDが使用されています。
うちの環境はImagickを実行するとApacheを巻き込んでクラッシュするので仕方なくというかPHPではメジャーで軽いGDほぼ一択。

しかしGDでJPEGを生成するとexifコメントに「CREATOR: gd-jpeg v1.0 (using IJG JPEG v90), quality = ...」って情報が追加されてしまいます。
たかが数バイトのデータですが、Yslow等のWebサイトの計測ページでは警告されマイナスポイントになりますし、要らないデータなのでない方がいいかなー。

なので、アップロードした画像と作成されるサムネイルのexif情報を削除するプラグインを作ってみました。
サムネイルのexif削除はGDを使用しているサーバー向けで、Imagickを使ってる場合はサムネイルにはexif情報は記録されません。

exifを削除するのに使用する物はImageMagickのスタンドアローンバージョン又はIMagick。
スタンドアローンを使う場合は、ImageMagickがインストールされている環境でないとダメ。

まずは完成PHPソース。

<?php
/*
Plugin Name: Remove EXIF
Plugin URI: http://blog.wolfs.jp/20160707-3638/
Description: アップロードした画像とサムネイル画像のexif情報を削除します。
Version: 1.0.0
Author: Kerberos
Author URI: http://blog.wolfs.jp/
*/
 
class removeExif {
    private $imagemagick_cli = true;
    private $imagemagick_path = '/usr/imagemagick/convert';
 
    public function __construct() {
        add_filter('wp_handle_upload', array($this, 'wp_handle_upload'));
        add_filter('wp_generate_attachment_metadata', array($this, 'wp_generate_attachment_metadata'), 10, 2);
    }
 
    public function wp_handle_upload($arg) {
        if ($this->check_mime($arg['type']) === true) {
            $this->remove_exif($arg['file']);
        }
 
        return $arg;
    }
 
    public function wp_generate_attachment_metadata($metadata, $attachment_id) {
        $dirArr = explode('/', $metadata['file']);
        $baseDir = wp_upload_dir(null, false);
        $uploadDir = $baseDir['basedir'].'/'.$dirArr[0].'/'.$dirArr[1].'/';
 
        foreach ($metadata['sizes'] as $entry) {
            if ($this->check_mime($entry['mime-type']) === true) {
                $this->remove_exif($uploadDir.$entry['file']);
            }
        }
 
        return $metadata;
    }
 
    private function check_mime($mime = null) {
        return ($mime === 'image/jpeg' || $mime === 'image/jpg');
    }
 
    private function remove_exif($filePath) {
        $filePath = addslashes($filePath);
 
        if (file_exists($filePath) === true) {
            if ($this->imagemagick_cli === true) {
                if (is_executable($this->imagemagick_path) === true) {
                    try {
                        exec('"'.$this->imagemagick_path.'" "'.$filePath.'" -strip "'.$filePath.'"');
                    } catch (Exception $e) {}
                }
            } else {
                if (class_exists('Imagick') === true) {
                    $im = new Imagick($filePath);
 
                    try {
                        $im->stripImage();
                        $im->writeImage($filePath);
                        $im->clear();
                        $im->destroy();
                    } catch (Exception $e) {}
                }
            }
        }
    }
}
 
new removeExif();
?>

かなり簡単なコード。(`・ω・)b

各ファンクションの簡単な説明は・・・
続きを読む