pretty code

2018年4月18日 星期三

ANSI/ISO/IEC 9899-1999

剛在網路上查了一下
電子檔要 US 60

https://webstore.ansi.org/RecordDetail.aspx?sku=INCITS%2fISO%2fIEC+9899-1999+(R2005)

Shit,好想買
又怕沒時間看

看看 Golang 的過過癮好了

2018年4月16日 星期一

2018年4月13日 星期五

C bool type

C 語言從 C99 開始,增加了 bool 這個關鍵字。

嚴格來說是 _Bool,bool 只是 marco,其目的是為了與 C++ 相容。

使用 bool 時,需 include <stdbool.h>。

至於我用的 TDM-gcc-32﹝4.9.2﹞,因為從此版開始,已經有支援一部份的 C99,故很多 C99 功能可以直接用。

但是預設是 -std=gnu89,我們可以看一下網頁說明。


-std
‘gnu89’
        GNU dialect of ISO C90 (including some C99 features). This is the default for C code.

這也說明了為什麼不用指定 -std=c99,就可以使用 bool、"//" C++ 單行註解以及 for loop variable i。

請參考底下連結:
https://gcc.gnu.org/onlinedocs/gcc-4.9.2/gcc/C-Dialect-Options.html#C-Dialect-Options

C 果然還是博大精深,我想我還太嫩了吧。

2018年3月30日 星期五

好想去高雄

由於被老婆大人限制人身自由,故不能隨意去想去的地方。

幸好訂購的東西已經來了,不得不說博客來的東西還是不怎麼好,邊邊有壓到的痕跡,只是不知道問題是出在誰那邊就是了,記得以前偶爾買書也是會這樣,所以我後來都去實體書店買。

趕快來安排一下,決定跟我的寶貝書放在一起,只是要放哪一格呢?





2018年3月16日 星期五

跳出當下

昨天下班到現在,一直在 parsing log 的 code 中鬼打牆

原本 code 已經寫好
故意測試一些 error case
想要把 error line 的訊息列印出來

因為 fgets 會將行尾的 \r \n 視為合法字元
如果列印出來 message 就會多斷行一次

於是寫了幾行 code 濾掉 \r \n
這時卻發現程式陷入了無限迴圈

明明只有幾行 code
不應該是 while loop 呀

後來才發現不是在這幾行 code while loop
而是因為將 \r \n 濾掉
導致昨天寫好的 code parsing rule 改變了

寫程式似乎很容易陷入盲點
總會以為 bug 是剛寫的 code 引起的

其實這樣說也沒錯
只是錯誤不一定就發生在那些 code 中

如果能夠跳出當下
將眼光放遠
不要執著在那幾行 code

現在應該已經改到下一階段了吧

這就是人生呀

2018年3月15日 星期四

c-warning: incompatible implicit declaration of built-in : function 'xxxx'

手上有一個專案
Server 和 Client 都是由我負責

由於使用了不同的程式語言
常常切換時腦袋都覺得快要打結了

更別提我自己慣用的 PHP 和 Golang
導致我常常要在這 4 種語法間切來切去

今天又回到改 Client code 的循環,這次要用 C parse log
這時就會覺得還是高階語言好用

個人習慣將相關功能寫到同一個 .c and .h
由於 parse log 是個新添加的功能
按照慣例,還是增加了新的檔案

為了處理 log 已經搞到頭昏腦脹
指標都不知道指到哪去了
偏偏又出現一堆這個 warning
因為想先完成 parse 功能
故先暫時忽略它

等到完成了 parse log 後
因為看不出來 code 那邊有問題
於是 google 了一下
才發現是沒有 include 用到的函式庫的標頭檔

由於是第一次遇到
感覺很新奇
畢竟我很少用函式沒 include

記錄一下

有興趣的可以看看 purpose 網友的文章

2018年3月13日 星期二

Use PHP to download Youtube video

最近很喜歡聽 "方宥心" 唱歌
加了好幾首 "最美的歌" 到喜歡的影片
於是就想試看看如何用程式來下載影片

網路上其實有很多線上服務可以做到
不過 RD 就是要捲起袖子自己來才有 fu

網路上查了一下
大概是利用 get_video_info 這個 api 配合影片 id
先取得影片 url ,接著就可以 download

舊的作法會再取得 'sig' 並串到 url 裡面(&singature=XXX)
但根據我 2018/03/14 的測試
url 裡面其實就有 'signature'
如果沒有,用 get_video_info 也會沒有
此時這個影片可能也不用下載了
因為一定會失敗
(但是線上服務是可以的)

不過這個 api 並不是官方 release 的
故以後還能不能用並不知道
再來也不是每個影片都能下載

步驟大概如下
1. 手動在 Youtube 喜歡的影片頁面,下載該頁面原始檔
2. 程式 parse 原始檔,找到影片的 id 及 title
3. 使用 get_video_info 取得 mp4 的下載 url
4. 使用 curl 下載檔案

github 連結


<?php

function downloadVideo($id, $title, $url, $video)
{
    $fp = fopen($video, "w");
    if (!$fp) {
        echo "$id $title can't create video file \n";
        return;
    }

    $ch = curl_init();

    if ($ch === false) {
        echo "$id $title curl_init error \n";
        fclose($fp);
        return;
    }

    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST , false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER , false);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_TIMEOUT, 600);
    curl_setopt($ch, CURLOPT_HEADER , false);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION , true);
    curl_setopt($ch, CURLOPT_AUTOREFERER , true);
    curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.146 Safari/537.36');
    curl_setopt($ch, CURLOPT_FILE, $fp);
    $con = curl_exec($ch);
    curl_close($ch);

    if ($con === false) {
        echo "$id $title download video error \n";
        fclose($fp);
        return;
    }

    fclose($fp);
}

function processVideo($id, $title, $video)
{
    $api = sprintf("http://www.youtube.com/get_video_info?video_id=%s", $id);

    $res = file_get_contents($api);

    if ($res === '') {
        echo "$id $title res is null \n";
        return;
    }

    $params = [];
    parse_str($res, $params);

    if (!isset($params['url_encoded_fmt_stream_map'])) {
        echo "$id $title url_encoded_fmt_stream_map error \n";
        return;
    }

    $s = $params['url_encoded_fmt_stream_map'];
    $streams = explode(',', $s);

    $realURL = '';
    for ($i = 0; $i < sizeof($streams); $i++) {
        $params = [];
        parse_str($streams[$i], $params);

        if (!isset($params['url']) || !isset($params['type']) || !isset($params['quality'])) {
            echo "$id $title params error \n";
            return;
        }

        $url = urldecode($params['url']);
        $type = urldecode($params['type']);
        $quality = urldecode($params['quality']);

        if (strpos($type, 'video/mp4') == 0) {
            $realURL = $url;
            if ($quality === 'medium') {
                break;
            }
        }
    }

    if ($realURL === '') {
        echo "$id $title has no mp4 type \n";
        return;
    }

    //echo "$title, $realURL\n";

    downloadVideo($id, $title, $realURL, $video);
}

// "youtube.txt" is the file that you use browser to save the page of your favorite videos.
$html = file_get_contents('youtube.txt');

$pattern = '/window\[\"ytInitialData\"\] = ({.*});/';

if (!preg_match($pattern, $html, $matchs)) {
    echo "can't find favorites \n";
    return;
}

$s = $matchs[1];

$json = json_decode($s, true);

$songs = $json['contents']['twoColumnBrowseResultsRenderer']['tabs'][0]
              ['tabRenderer']['content']['sectionListRenderer']['contents'][0]
              ['itemSectionRenderer']['contents'][0]
              ['playlistVideoListRenderer']['contents'];

for ($i = 0; $i < sizeof($songs); $i++) {
    $title = $songs[$i]['playlistVideoRenderer']['title']['simpleText'];
    $title = mb_convert_encoding($title, "big5", "utf-8");
    $title = str_replace([' ', '?'], ['', ''], $title);

    $id = $songs[$i]['playlistVideoRenderer']['videoId'];

    //echo "$id $title \n";

    $video = sprintf("%s\\%s.mp4", __DIR__, $title);

    processVideo($id, $title, $video);

    sleep(10);
}