MP4(m4a)とbps

MP4とは、MPEG-4形式の圧縮動画データを格納するファイル形式の一つて、静止画像や字幕といったデータはもちろんMPEGによって定義されたデジタル音声と動画をひとつのファイルに保存することができるコンテナ形式。MP4はApple社のメディア技術QuickTimeのファイル形式を元に策定されたISO/IEC 14496 Part 12の派生フォーマットで、従来のQuickTime形式の多くを踏襲した構造となっている。

mp3は音声を圧縮するときの方式(フォーマット)で,できあがったファイルの拡張子もmp3。 mp4は動画と音声を両方格納するための枠組み

192kbps以上ならたいていはmp3が高音質になるらしい。中には,128kbpsくらいで逆転することもあるとのこと。

ビットレートが高ければ高いほど、画質・音質が向上。
192kbpsとは1秒間に192kビットのデータが走っていること。

レコチョクはm4aを使われてますね。

audio/mpeg

MPEGは「音声、映像関連の規格」
MP3は「音声データを扱うときの規格のひとつ」
MIMEタイプは「ファイルの種類を表す情報」

mp3ファイルはaudioタグで囲う

<h1>MP3の再生</h1>
<audio src="test.mp3" controls></audio>

PHPで浜崎あゆみの昔のアルバムを聞きまくろう

10個リクエストを送ります。
重複してレスポンスが返ってくるので、array_uniqueで重複を削除します。

<?php

require 'vendor/autoload.php';

$session = new SpotifyWebAPI\Session(
    'id',
    'secret',
    'http://192.168.33.10:8000/callback/'
);

$api = new SpotifyWebAPI\SpotifyWebAPI();

$count = 10;

if (isset($_GET&#91;'code'&#93;)) {
    $session->requestAccessToken($_GET['code']);
    $api->setAccessToken($session->getAccessToken());


    $tracks = $api->search('浜崎あゆみ', 'track', array(
        'limit' => $count
        ));
 
// print_r('<pre>');
// var_dump($tracks);
// print_r('</pre>');
    for($i=0; $i<$count; $i++){
        $track_id&#91;&#93; = $tracks->tracks->items[$i]->album->id;
    }


    // print_r($track_id);
} else {
    $options = [
        'scope' => [
            'user-read-email',
        ],
    ];

    header('Location: ' . $session->getAuthorizeUrl($options));
    die();
}

$track_id = array_unique($track_id);
foreach($track_id as $value){
    echo "<iframe src=\"https://embed.spotify.com/?uri=spotify:album:".$value."\" width=\"300\" height=\"380\" frameborder=\"0\" allowtransparency=\"true\"></iframe>";
}
?>

あ、これは結構いい。昔の曲が聞ける。

LUNA SEA行ってみよう。 mothersはかっこよかった。

一曲全部じゃないのが惜しいが。

PHPで浜崎あゆみを聞いてみよう

spotify api
$api->searchでtrackが返ってきます。

<?php
require 'vendor/autoload.php';
$session = new SpotifyWebAPI\Session(
    'id',
    'secret',
    'http://192.168.33.10:8000/callback/'
);

$api = new SpotifyWebAPI\SpotifyWebAPI();
if (isset($_GET&#91;'code'&#93;)) {
    $session->requestAccessToken($_GET['code']);
    $api->setAccessToken($session->getAccessToken());
    $tracks = $api->search('浜崎あゆみ', 'track', array(
        'limit' => 1
        ));
    $track_id = $tracks->tracks->items[0]->album->id;
    print_r($track_id);
} else {
    $options = [
        'scope' => [
            'user-read-email',
        ],
    ];
    header('Location: ' . $session->getAuthorizeUrl($options));
    die();
}
// print_r('<pre>');
// var_dump($tracks);
// print_r('</pre>');
?>
<h1>spotify</h1>
<iframe src="https://embed.spotify.com/?uri=spotify:album:<?php echo $track_id; ?>" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>

まあまあいいんだけど、全部サビ前からサビの30秒位なんだよな。
1曲全部聞けないと、物足りない感が尋常ではない。

あ、iframeこんな感じです。うーん、違うな。やっぱりイントロから聞けないと絶対ダメでしょ。

spotify api invalid redirect uri

index.php

$session = new SpotifyWebAPI\Session(
    'client id',
    'client secret',
    'http://192.168.33.10:8000/callback'
);

spotify

invalid URIのレスポンスが返ってくるため、stackoverflowを見ていたら、

stackoverflow
https://stackoverflow.com/questions/32956443/invalid-redirect-uri-on-spotify-auth
app.js:
var redirect_uri = ‘http://localhost:8888/callback’;
Spotify > My application:
http://localhost:8888/callback/

それでもエラーで
なんでだろうと思っていたら、
myappとlocalで、callback urlは完全一致(バックスラッシュ)にしないといけないようです。
http://192.168.33.10:8000/callback/
http://192.168.33.10:8000/callback/

泣きたくなってきた。

mysql テーブル連携

まず、一つ目のテーブルを作くってデータを入れます。

create table cake.base(
	id int unsigned auto_increment primary key,
	code int,
	name varchar(255)
);

insert into base(code, name) values
('3689', 'イグニス'),
('4579', 'ラクオリア創薬'),
('3825', 'リミックスポイント');

二つ目のテーブルを作って、こちらにもデータを挿入。

create table cake.data(
	id int unsigned auto_increment primary key,
	code int,
	price int,
	time datetime default null
);

insert into cake.data(code, price, time) values
('3689', '3240', now()),
('3689', '3245', now()),
('3689', '3250', now()),
('3689', '3245', now());

INNER JOINでカラムを指定して結合する
SELECT base.code, base.name, data.price, data.time FROM base INNER JOIN data ON base.code = data.code;

OUTER JOIN
SELECT base.code, base.name, data.price, data.time FROM base LEFT OUTER JOIN data ON base.code = data.code;
dataが入っていないラクオリア創薬、リミックスポイントもselectされます。

更にテーブルを連結する場合も、joinでok
create table cake.market(
id int unsigned auto_increment primary key,
code int,
market varchar(255)
);

insert into market(code, market) values
(‘3689’, ‘マザーズ’),
(‘4579’, ‘ジャスダック’),
(‘3825’, ‘東証二部’);

SELECT base.code, base.name, data.price, data.time, market.market FROM base JOIN market ON base.code = market.code JOIN data ON base.code = data.code;

cake migration

// making migration 
[vagrant@localhost myblog]$ bin/cake bake migration_snapshot Initial

[vagrant@localhost myblog]$ bin/cake migrations status
using migration paths
 - /home/vagrant/fw/myblog/config/Migrations
using seed paths
 - /home/vagrant/fw/myblog/config/Seeds
using environment default

 Status  Migration ID    Migration Name
-----------------------------------------
     up  20180306042845  Initial


[vagrant@localhost myblog]$ bin/cake bake migration CreateComments post_id:integer body:string created modified

Creating file /home/vagrant/fw/myblog/config/Migrations/20180306043056_CreateComments.php
Wrote `/home/vagrant/fw/myblog/config/Migrations/20180306043056_CreateComments.php

[vagrant@localhost myblog]$ bin/cake migrations migrate
`

mysqlで確認

mysql> use cake
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
mysql> show tables;
+----------------+
| Tables_in_cake |
+----------------+
| comments       |
| phinxlog       |
| posts          |
+----------------+
3 rows in set (0.00 sec)

すげー

commentController

<?php

namespace App\Controller;

class CommentsController extends AppController
{
	public function  add()
	{
		$this->viewBuilder()->layout('my_layout');
		$comment = $this->Comments->newEntity();
		if($this->request->is('post')){
			$comment = $this->Comments->patchEntity($comment, $this->request->data);
			if($this->Comments->save($comment)){
				$this->Flash->success('Comment Add Success!');
				return $this->redirect(['controller'=>'Posts','action'=>'view', $comment->post_id]);
			}else {
				$this->Flash->success('Error');
			}
		}
		$this->set('post', $comment);
	}

	public function delete($id = null)
	{
		$this->viewBuilder()->layout('my_layout');
		$this->request->allowMethod(['post', 'delete']);
		$comment = $this->Comments->get($id);
		if($this->Comments->delete($comment)){
			$this->Flash->success('Comment Delete Success!');
			
		}else {
			$this->Flash->success('Error');
		}
		return $this->redirect(['controller'=>'Posts','action'=>'view', $comment->post_id]);

	}
}
?>

cake update

controllerでgetして、$this->Posts->save

public function edit($id = null)
	{
		$this->viewBuilder()->layout('my_layout');
		$post = $this->Posts->get($id);
		if($this->request->is(['post','patch','put'])){
			$post = $this->Posts->patchEntity($post, $this->request->data);
			if($this->Posts->save($post)){
				$this->Flash->success('Edit Success!');
				return $this->redirect(['action'=>'index']);
			}else {
				$this->Flash->success('Error');
			}
		}
		$this->set('post', $post);
	}

deleteは $this->Posts->deleteになる

public function edit($id = null)
	{
		$this->viewBuilder()->layout('my_layout');
		$this->request->allowMethod(['post', 'delete']);
		$post = $this->Posts->get($id);
		if($this->Posts->delete($post)){
			$this->Flash->success('Delete Success!');
			
		}else {
			$this->Flash->success('Error');
		}
		return $this->redirect(['action'=>'index']);

	}

cake form helper

<?= $this->Form->create($post); ?>
<?= $this->Form->input('title'); ?>
<?= $this->Form->input('body', ['rows'=> '3']); ?>
<?= $this->Form->button('Add'); ?>
<?= $this->Form->end(); ?>

なるほど、だんだんテンションが下がってきた。

DBへのinsertをcontrollerで書きます。

public function  add()
	{
		$this->viewBuilder()->layout('my_layout');
                $post = $this->Posts->newEntity();
		if($this->request->is('post')){
			$post = $this->Posts->patchEntity($post, $this->request->data);
			$this->Posts->save($post);
			return $this->redirect(['action'=>'index']);
		}
		$this->set('post', $post);
	}

validatorはmodelに書きます。

<?php

namespace App\Model\Table;

use Cake\ORM\Table;
use Cake\Validation\Validator;

class PostsTable extends Table
{
	public function initialize(array $config)
	{
		$this->addBehavior('Timestamp');
	}

	public function validationDefault(Validator $validator)
		{
			$validator
			->notEmpty('title')
			->requirePresence('title')
			->notEmpty('body')
			->requirePresence('body')
			->add('body', [
				'length' => [
					'rule' => ['minLength', 10],
					'message' => 'body length must be 10+'
					]
				]);
		return $validator;
	}
}

controllerでvalidationの設定

public function  add()
	{
		$this->viewBuilder()->layout('my_layout');
		$post = $this->Posts->newEntity();
		if($this->request->is('post')){
			$post = $this->Posts->patchEntity($post, $this->request->data);
			if($this->Posts->save($post)){
				return $this->redirect(['action'=>'index']);
			}else {
				// error
			}
		}
		$this->set('post', $post);
	}

cake Linkの作成

index.ctp

Htmlヘルパーを使う場合
Html->linkとする テーブルのカラムを指定し、コントローラーとアクションを作成。
うーん、慣れるまで時間がかかりそう。

<?php foreach($posts as $post):?>
		<li><?= $this->Html->link($post->title, ['controller'=>'Posts', 'action'=>'view']); ?></li>
	<?php endforeach; ?> 

ブラウザで確認。反映されてますね。

urlヘルパーを使う場合

<a href="<?= $this->Url->build(['action'=>'view', $post->id]); ?>">
		<?= h($post->title); ?></a>

Htmlヘルパーの方がコード量が少なく楽そうに見えます。