M3u8文件下载并合并

原由:

最近在极客时间上购买一波 Go语言从入门到实战 视频课程,但又不想受到网络环境的限制,所以就有了这篇文章。

操作:

一、ffmpeg 下载和安装

  • mac OS X :
1
2
3
4
5
# 安装 homebrew
/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

# 安装 ffmpeg
brew install ffmpeg
  • Linux 安装:
1
yum install ffmpeg

二、使用ffmpeg下载且合并成mp4

1
2
3
ffmpeg  -i "http://xxxxxx/video/movie.m3u8" -vcodec copy -acodec copy -absf aac_adtstoasc  output.mp4

# m3u8 链接, output.mp4 输出文件名

三、使用Go实现批量合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package main

import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"os/exec"
)

type Datas struct {
Data List `json:"data"`
}

type List struct {
L []VideoMap `json:"list"`
}

type VideoMap struct {
ArticleTitle string `json:"article_title"`
VideoMediaMap struct {
HD struct {
URL string `json:"url"`
Size int64 `json:"size"`
} `json:"hd"`
} `json:"video_media_map"`
}

var (
video Datas
path string = "/Users/gxm/Movies/time_go/" // 保存文件的路径
)

func main() {
body, err := ioutil.ReadFile("./ Go语言从入门到实战.json") # m3u8 视频列表的json文件
if err != nil {
log.Fatalln(err)
}

err = json.Unmarshal(body, &video)

if err != nil {
log.Fatalln(err)
}

// fmt.Println(video)

for _, v := range video.L {
fmt.Println(v.VideoMediaMap.HD.URL, v.ArticleTitle)
merge(v.VideoMediaMap.HD.URL, v.ArticleTitle)
}
}

//ffmpeg -i "http://xxxxxx/video/movie.m3u8" -vcodec copy -acodec copy -absf aac_adtstoasc output.mp4
func merge(url string, name string) {

cmd := exec.Command("ffmpeg", "-i", url, "-vcodec", "copy", "-acodec", "copy", "-absf", "aac_adtstoasc", path+name+".mp4")
message, err := cmd.CombinedOutput()

if err != nil {
log.Println(err)
}

log.Println(string(message))
}

总结:

要是不想把m3u8的数据json下载本地在运行的话,你可以使用爬虫模拟登录去获m3u8的数据,然后在去执行merge函数来合并。

本文章仅提供学习,如有违规和侵权请联系本人。

Go获取服务器ip

排查负载均衡服务器中某个IP指定的服务出现故障

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package main

import (
"log"
"net/http"
"net/http/httptrace"
)

func main() {
req, err := http.NewRequest("GET", "https://example.com/", nil)
if err != nil {
log.Fatal(err)
}

trace := &httptrace.ClientTrace{
GotConn: func(connInfo httptrace.GotConnInfo) {
log.Printf("resolved to: %s", connInfo.Conn.RemoteAddr())
},
}

req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))

client := &http.Client{}
_, err := client.Do(req)
if err != nil {
log.Fatal(err)
}
}

U盘启动器

使用MacBook pro 制作windows 10的u盘启动器

命令制作

1
2
3
4
5
diskutil list # 列出本机所有的磁盘或分区

diskutil eraseDisk MS-DOS "WINDOWS10" MBR disk2 # 把当前的u盘格式化并改名为 windows10

cp -rp /Volumes/VolumeName/* /Volumes/WINDOWS10/ # volumeName 所指windows镜像挂载后的名称

图:

1、

2、

Dnmp

Docker搭建php开发环境

Nginx:

拉取nginx镜像

1
docker pull nginx

启动并运行nginx

1
docker run -d -p 8080:80 -v /Users/gxm/docker/nginx:/etc/nginx/conf.d -v /Users/gxm/docker/html --name=nginx_ nginx

参数说明:

  • -d: 后台运行容器,并返回容器ID
  • -p: 将容器的端口映射到宿主机的端口
  • -v:将宿主机目录挂载到容器目录下
  • —name:为容器指定一个名称
  • -link: 链接另一个容器

PHP7.2

拉取php:7.2-fpm

1
docker pull php:7.2-fpm

启动并运行php

1
2
3
4
docker run -d -p 9000:9000 -v /Users/gxm/docker/html:/usr/share/nginx/html --name=php72 php:7.2-fpm

# 获取运行的php72 在docker中的ip地址
docker inspect php72

MySQL5.7:

1
2
3
docker pull mysql:5.7

docker run -d -p 3306:3306 -e MYSQL_ROOT_PASSWORD=123456 --name mysql mysql:5.7

注意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# mysql 8.0 的情况下
plugin caching_sha2_password could not be loaded

docker exec -it mysql /bin/bash
# 登录数据库

mysql -uroot -p {your password}
# 使用mysql数据库
mysql>use mysql

# 修改数据库
mysql> ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '{your password}';

# 重新修改密码后可连接成功
mysql> alter user 'root'@'%' identified by '123456';

# 刷新数据库
mysql> flush privileges;

参数:

  • -e:指定环境变量,容器中可以使用该环境变量

Nginx—>PHP 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
server {
listen 80;
server_name _;
root /usr/share/nginx/html;
index index.php index.html index.htm;
#charset koi8-r;

access_log /dev/null;
#access_log /var/log/nginx/nginx.localhost.access.log main;
error_log /var/log/nginx/error.log warn;

#error_page 404 /404.html;

# redirect server error pages to the static page /50x.html
#
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}

# proxy the PHP scripts to Apache listening on 127.0.0.1:80
#
#location ~ \.php$ {
# proxy_pass http://127.0.0.1;
#}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
fastcgi_pass 172.17.0.3:9000; # php72 容器的ip, 获取 docker inspect php容器的名称或容器ID, 假如使用-link 参数的情况下,这里填写链接容器的名称 phpfmp, --link php72:phpfmp
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param SCRIPT_FILENAME /usr/share/nginx/html$fastcgi_script_name; # /var/www/html 是php文件执行目录
}

# deny access to .htaccess files, if Apache's document root
# concurs with nginx's one
#
#location ~ /\.ht {
# deny all;
#}
}


// 加载配置
docker exec -ti nginx_ bash

service nginx reload

PHP安装扩展:

1
2
3
4
5
docker exec -ti php72 bash

cd /usr/local/bin

docker-php-ext-install pdo pdo-mysql // 等等扩展

参数:

  • -t:为容器重新分配一个伪输入终端,通常与 -i 同时使用
  • -i:以交互模式运行容器,通常与 -t 同时使用

Window

Window 10 激活命令

1、Ctrl + R 在运行中输入cmd

2、输入slmgr.vbs /upk (此时弹出窗口显未“已成功卸载了产品密钥”)

3、输入slmgr /ipk W269N-WFGWX-YVC9B-4J6C9-T83GX (弹出窗口提示:“成功的安装了产品密钥”)

4、输入slmgr /skms zh.us.to (弹出窗口提示:“密钥管理服务计算机名成功的设置为 zh.us.to”)

5、最后输入slmgr /ato(弹出窗口提示:“成功的激活了产品”)

注:如有侵权问题,请联系本人,删除。

Duplicate-Emails

leetcode - 182. 查找重复的电子邮箱

题目:

编写一个 SQL 查询,查找 Person 表中所有重复的电子邮箱。

示例:

1
2
3
4
5
6
7
+----+---------+
| Id | Email |
+----+---------+
| 1 | [email protected] |
| 2 | [email protected] |
| 3 | [email protected] |
+----+---------+

根据以上输入,你的查询应返回以下结果:

1
2
3
4
5
+---------+
| Email |
+---------+
| [email protected] |
+---------+

说明:所有电子邮箱都是小写字母。

解答:

  • SQL
    1
    select Email from Person where Id in (select ID from Person group by Email having count(Email) >= 2)

Valid-Parentheses

leetcode - 20. 有效的括号

题目:

1
2
3
4
5
6
7
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。

有效字符串需满足:

左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。

解答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
// 第一种解法
func isValid(s string) bool {
var tmp []string

arr := strings.Split(s, "")
for _, x := range arr {
c := x
if c == "(" || c == "[" || c == "{" {
tmp = append(tmp, c)
} else {
if len(tmp) == 0 {
return false
}

charTop := tmp[len(tmp)-1]
tmp = append(tmp[:len(tmp)-1], tmp[len(tmp):]...)
if c == ")" && charTop != "(" {
return false
}
if c == "]" && charTop != "[" {
return false
}

if c == "}" && charTop != "{" {
return false
}
}
}

if len(tmp) != 0 {
return false
}

return true
}

// 第二种解法:
func isValid(s string) bool {
var (
tmp []string
True bool = true
)
validMap := map[string]string{
")": "(",
"}": "{",
"]": "[",
}

sArray := strings.Split(s, "")

for _, x := range sArray {
// fmt.Println(x)
if _, ok := validMap[x]; !ok {
tmp = append(tmp, x)
continue
}
if len(tmp) != 0 {
v := tmp[len(tmp)-1]
tmp = append(tmp[:len(tmp)-1], tmp[len(tmp):]...)
if v != validMap[x] {
True = false
break
}
} else {
True = false
break
}
}
if len(tmp) != 0 {
True = false
}

return True
}

Two-Sum

# leetcode - 1. 两数之和

题目:

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。

你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。

示例:

1
2
3
4
给定 nums = [2, 7, 11, 15], target = 9

因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

解答:

  • golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
func twoSum(nums []int, target int) []int {
hum_map := make(map[int]int)

for i, x := range nums {
mus := target - x
if _, ok := hum_map[mus]; ok {
return []int{i, hum_map[mus]}
}

hum_map[x] = i
}

return nil
}
  • python
1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hum_map = dict()
for i, x in enumerate(nums):
if target - x in hum_map:
return [i, hum_map[target - x]]
hum_map[x] = i

Merging

归并排序

  • 时间复杂度 O(n)
  • 空间复杂度 O(log2n)

PHP:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
function merge(array $left, array $rigth) : array 
{
$result = array();

while (count($left) && count($rigth)) {
$result[] = $left[0] < $rigth[0] ? array_shift($left) : array_shift($rigth);
}

return array_merge($result, $left, $rigth);
}

function al_merge_sort(array $arr) : array
{
$len = count($arr);
if ($len <= 1) {
return $arr;
}

$mid = intval($len / 2);

$left = array_slice($arr, 0, $mid);
$rigth = array_slice($arr, $mid);

$left = al_merge_sort($left);
$rigth = al_merge_sort($rigth);

return merge($left, $rigth);
}

print_r(al_merge_sort([9, 3, 5, 6, 7, 1, 2, 55, 56]));

// Array
// (
// [0] => 1
// [1] => 2
// [2] => 3
// [3] => 5
// [4] => 6
// [5] => 7
// [6] => 9
// [7] => 55
// [8] => 56
// )

Go:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package main

import (
"fmt"
)

func merge(left, rigth []int) (result []int) {

l, r := 0, 0

for l < len(left) && r < len(rigth) {
if left[l] < rigth[r] {
result = append(result, left[l])
l ++
} else {
result = append(result, rigth[r])
r ++
}
}

result = append(result, left[l:]...)
result = append(result, rigth[r:]...)

return
}

func al_merg_sort(arr []int) []int {
length := len(arr)

if length <= 1 {
return arr
}

mid := length / 2

left := al_merg_sort(arr[:mid])
rigth := al_merg_sort(arr[mid:])

return merge(left, rigth)
}

func main() {
arr := []int{31, 4, 5, 27, 18, 1 ,3, 6, 8}
fmt.Println(al_merg_sort(arr))
}

Length-of-Last-Word

leetcode - 58. 最后一个单词的长度

题目:

给定一个仅包含大小写字母和空格 ‘ ‘ 的字符串,返回其最后一个单词的长度。

如果不存在最后一个单词,请返回 0 。

说明:一个单词是指由字母组成,但不包含任何空格的字符串。

示例:

1
2
输入: "Hello World"
输出: 5

解答:

  • golang
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
func lengthOfLastWord(s string) int {
strArray := strings.Split(s, " ")
mun := len(strArray)

if mun <= 1 {
return len([]byte(strArray[0]))
}
var tmp string
for _, x := range strArray {
if x == "" {
continue
}
tmp = x
}

return len([]byte(tmp))
}
  • Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Solution:
def lengthOfLastWord(self, s):
"""
:type s: str
:rtype: int
"""
array = s.split()
if len(array) >= 1:
return len(array[-1])
else:
return 0

solution = Solution()
print(solution.lengthOfLastWord("hello world"))