@ormoshe/js-video-url-parser 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/jsVideoUrlParser.js +1571 -0
- package/dist/jsVideoUrlParser.min.js +1 -0
- package/lib/base.d.ts +2 -0
- package/lib/base.js +3 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +18 -0
- package/lib/provider/allocine.d.ts +13 -0
- package/lib/provider/allocine.js +36 -0
- package/lib/provider/base-provider.d.ts +13 -0
- package/lib/provider/canalplus.d.ts +13 -0
- package/lib/provider/canalplus.js +46 -0
- package/lib/provider/coub.d.ts +13 -0
- package/lib/provider/coub.js +54 -0
- package/lib/provider/dailymotion.d.ts +14 -0
- package/lib/provider/dailymotion.js +70 -0
- package/lib/provider/facebook.d.ts +14 -0
- package/lib/provider/facebook.js +78 -0
- package/lib/provider/loom.d.ts +13 -0
- package/lib/provider/loom.js +51 -0
- package/lib/provider/soundcloud.d.ts +16 -0
- package/lib/provider/soundcloud.js +125 -0
- package/lib/provider/teachertube.d.ts +14 -0
- package/lib/provider/teachertube.js +110 -0
- package/lib/provider/ted.d.ts +14 -0
- package/lib/provider/ted.js +96 -0
- package/lib/provider/tiktok.d.ts +14 -0
- package/lib/provider/tiktok.js +50 -0
- package/lib/provider/twitch.d.ts +15 -0
- package/lib/provider/twitch.js +150 -0
- package/lib/provider/vimeo.d.ts +14 -0
- package/lib/provider/vimeo.js +89 -0
- package/lib/provider/voomly.d.ts +14 -0
- package/lib/provider/voomly.js +46 -0
- package/lib/provider/wistia.d.ts +15 -0
- package/lib/provider/wistia.js +112 -0
- package/lib/provider/youku.d.ts +13 -0
- package/lib/provider/youku.js +83 -0
- package/lib/provider/youtube.d.ts +15 -0
- package/lib/provider/youtube.js +205 -0
- package/lib/testUrls.js +11 -0
- package/lib/urlParser.d.ts +23 -0
- package/lib/urlParser.js +81 -0
- package/lib/util.js +104 -0
- package/package.json +59 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { VideoInfo } from '../urlParser';
|
|
2
|
+
|
|
3
|
+
export interface VoomlyUrlParameters {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type VoomlyMediaTypes = 'video';
|
|
8
|
+
|
|
9
|
+
export interface VoomlyVideoInfo extends VideoInfo<VoomlyUrlParameters, VoomlyMediaTypes> {
|
|
10
|
+
provider: 'voomly';
|
|
11
|
+
channel: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type VoomlyParseResult = VoomlyVideoInfo | undefined;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
const { combineParams } = require('../util');
|
|
2
|
+
|
|
3
|
+
function Voomly() {
|
|
4
|
+
this.provider = 'voomly';
|
|
5
|
+
this.defaultFormat = 'long';
|
|
6
|
+
this.formats = {
|
|
7
|
+
long: this.createLongUrl,
|
|
8
|
+
};
|
|
9
|
+
this.mediaTypes = {
|
|
10
|
+
VIDEO: 'video',
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
module.exports = Voomly;
|
|
15
|
+
|
|
16
|
+
Voomly.prototype.parseUrl = function(url) {
|
|
17
|
+
var match = url.match(
|
|
18
|
+
/(?:v|embed)\/([a-zA-Z\d]+)/i
|
|
19
|
+
);
|
|
20
|
+
return match ? match[1] : undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
Voomly.prototype.parse = function(url, params) {
|
|
24
|
+
var result = {
|
|
25
|
+
mediaType: this.mediaTypes.VIDEO,
|
|
26
|
+
params: params,
|
|
27
|
+
id: this.parseUrl(url),
|
|
28
|
+
};
|
|
29
|
+
return result.id ? result : undefined;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
Voomly.prototype.createUrl = function(baseUrl, vi, params) {
|
|
33
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
var url = baseUrl + vi.id;
|
|
38
|
+
url += combineParams(params);
|
|
39
|
+
return url;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
Voomly.prototype.createLongUrl = function(vi, params) {
|
|
43
|
+
return this.createUrl('https://share.voomly.com/v/', vi, params);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
require('../base').bind(new Voomly());
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VideoInfo } from '../urlParser';
|
|
2
|
+
|
|
3
|
+
export interface WistiaUrlParameters {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
start?: number;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type WistiaMediaTypes = 'video' | 'embedvideo';
|
|
9
|
+
|
|
10
|
+
export interface WistiaVideoInfo extends VideoInfo<WistiaUrlParameters, WistiaMediaTypes> {
|
|
11
|
+
provider: 'wistia';
|
|
12
|
+
channel?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type WistiaParseResult = WistiaVideoInfo | undefined;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const {
|
|
2
|
+
combineParams,
|
|
3
|
+
getTime,
|
|
4
|
+
} = require('../util');
|
|
5
|
+
|
|
6
|
+
function Wistia() {
|
|
7
|
+
this.provider = 'wistia';
|
|
8
|
+
this.alternatives = [];
|
|
9
|
+
this.defaultFormat = 'long';
|
|
10
|
+
this.formats = {
|
|
11
|
+
long: this.createLongUrl,
|
|
12
|
+
embed: this.createEmbedUrl,
|
|
13
|
+
embedjsonp: this.createEmbedJsonpUrl,
|
|
14
|
+
};
|
|
15
|
+
this.mediaTypes = {
|
|
16
|
+
VIDEO: 'video',
|
|
17
|
+
EMBEDVIDEO: 'embedvideo',
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
module.exports = Wistia;
|
|
22
|
+
|
|
23
|
+
Wistia.prototype.parseUrl = function(url) {
|
|
24
|
+
var match = url.match(
|
|
25
|
+
/(?:(?:medias|iframe)\/|wvideo=)([\w-]+)/
|
|
26
|
+
);
|
|
27
|
+
return match ? match[1] : undefined;
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
Wistia.prototype.parseChannel = function(url) {
|
|
31
|
+
var match = url.match(
|
|
32
|
+
/(?:(?:https?:)?\/\/)?([^.]*)\.wistia\./
|
|
33
|
+
);
|
|
34
|
+
var channel = match ? match[1] : undefined;
|
|
35
|
+
if (channel === 'fast' || channel === 'content') {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return channel;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
Wistia.prototype.parseParameters = function(params, result) {
|
|
42
|
+
if (params.wtime) {
|
|
43
|
+
params.start = getTime(params.wtime);
|
|
44
|
+
delete params.wtime;
|
|
45
|
+
}
|
|
46
|
+
if (params.wvideo === result.id) {
|
|
47
|
+
delete params.wvideo;
|
|
48
|
+
}
|
|
49
|
+
return params;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
Wistia.prototype.parseMediaType = function(result) {
|
|
53
|
+
if (result.id && result.channel) {
|
|
54
|
+
return this.mediaTypes.VIDEO;
|
|
55
|
+
} else if (result.id) {
|
|
56
|
+
delete result.channel;
|
|
57
|
+
return this.mediaTypes.EMBEDVIDEO;
|
|
58
|
+
} else {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
Wistia.prototype.parse = function(url, params) {
|
|
64
|
+
var result = {
|
|
65
|
+
id: this.parseUrl(url),
|
|
66
|
+
channel: this.parseChannel(url),
|
|
67
|
+
};
|
|
68
|
+
result.params = this.parseParameters(params, result);
|
|
69
|
+
result.mediaType = this.parseMediaType(result);
|
|
70
|
+
|
|
71
|
+
if (!result.id) {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return result;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
Wistia.prototype.createUrl = function(vi, params, url) {
|
|
79
|
+
if (params.start) {
|
|
80
|
+
params.wtime = params.start;
|
|
81
|
+
delete params.start;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
url += combineParams(params);
|
|
85
|
+
|
|
86
|
+
return url;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
Wistia.prototype.createLongUrl = function(vi, params) {
|
|
90
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
var url = 'https://' + vi.channel + '.wistia.com/medias/' + vi.id;
|
|
94
|
+
return this.createUrl(vi, params, url);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
Wistia.prototype.createEmbedUrl = function(vi, params) {
|
|
98
|
+
if (!vi.id || !(vi.mediaType === this.mediaTypes.VIDEO || vi.mediaType === this.mediaTypes.EMBEDVIDEO)) {
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
var url = 'https://fast.wistia.com/embed/iframe/' + vi.id;
|
|
102
|
+
return this.createUrl(vi, params, url);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
Wistia.prototype.createEmbedJsonpUrl = function(vi) {
|
|
106
|
+
if (!vi.id || !(vi.mediaType === this.mediaTypes.VIDEO || vi.mediaType === this.mediaTypes.EMBEDVIDEO)) {
|
|
107
|
+
return undefined;
|
|
108
|
+
}
|
|
109
|
+
return 'https://fast.wistia.com/embed/medias/' + vi.id + '.jsonp';
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
require('../base').bind(new Wistia());
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { VideoInfo } from '../urlParser';
|
|
2
|
+
|
|
3
|
+
export interface YoukuUrlParameters {
|
|
4
|
+
[key: string]: any;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export type YoukuMediaTypes = 'video';
|
|
8
|
+
|
|
9
|
+
export interface YoukuVideoInfo extends VideoInfo<YoukuUrlParameters, YoukuMediaTypes> {
|
|
10
|
+
provider: 'youku';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type YoukuParseResult = YoukuVideoInfo | undefined;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
const {combineParams} = require('../util');
|
|
2
|
+
|
|
3
|
+
function Youku() {
|
|
4
|
+
this.provider = 'youku';
|
|
5
|
+
this.defaultFormat = 'long';
|
|
6
|
+
this.formats = {
|
|
7
|
+
embed: this.createEmbedUrl,
|
|
8
|
+
long: this.createLongUrl,
|
|
9
|
+
flash: this.createFlashUrl,
|
|
10
|
+
static: this.createStaticUrl,
|
|
11
|
+
};
|
|
12
|
+
this.mediaTypes = {
|
|
13
|
+
VIDEO: 'video',
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = Youku;
|
|
18
|
+
|
|
19
|
+
Youku.prototype.parseUrl = function(url) {
|
|
20
|
+
var match = url.match(
|
|
21
|
+
/(?:(?:embed|sid)\/|v_show\/id_|VideoIDS=)([a-zA-Z0-9]+)/
|
|
22
|
+
);
|
|
23
|
+
return match ? match[1] : undefined;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
Youku.prototype.parseParameters = function(params) {
|
|
27
|
+
if (params.VideoIDS) {
|
|
28
|
+
delete params.VideoIDS;
|
|
29
|
+
}
|
|
30
|
+
return params;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
Youku.prototype.parse = function(url, params) {
|
|
34
|
+
var _this = this;
|
|
35
|
+
var result = {
|
|
36
|
+
mediaType: this.mediaTypes.VIDEO,
|
|
37
|
+
id: _this.parseUrl(url),
|
|
38
|
+
params: _this.parseParameters(params),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
if (!result.id) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
Youku.prototype.createUrl = function(baseUrl, vi, params) {
|
|
48
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
var url = baseUrl + vi.id;
|
|
52
|
+
|
|
53
|
+
url += combineParams(params);
|
|
54
|
+
return url;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
Youku.prototype.createEmbedUrl = function(vi, params) {
|
|
59
|
+
return this.createUrl('http://player.youku.com/embed/', vi, params);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
Youku.prototype.createLongUrl = function(vi, params) {
|
|
63
|
+
return this.createUrl('http://v.youku.com/v_show/id_', vi, params);
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
Youku.prototype.createStaticUrl = function(vi, params) {
|
|
67
|
+
return this.createUrl(
|
|
68
|
+
'http://static.youku.com/v1.0.0638/v/swf/loader.swf?VideoIDS=',
|
|
69
|
+
vi, params
|
|
70
|
+
);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
Youku.prototype.createFlashUrl = function(vi, params) {
|
|
74
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
var url = 'http://player.youku.com/player.php/sid/' + vi.id + '/v.swf';
|
|
78
|
+
|
|
79
|
+
url += combineParams(params);
|
|
80
|
+
return url;
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
require('../base').bind(new Youku());
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { VideoInfo } from '../urlParser';
|
|
2
|
+
|
|
3
|
+
export interface YouTubeUrlParameters {
|
|
4
|
+
start?: number;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export type YouTubeMediaTypes = 'video' | 'playlist' | 'share' | 'channel';
|
|
9
|
+
|
|
10
|
+
export interface YouTubeVideoInfo extends VideoInfo<YouTubeUrlParameters, YouTubeMediaTypes> {
|
|
11
|
+
provider: 'youtube';
|
|
12
|
+
list?: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export type YouTubeParseResult = YouTubeVideoInfo | undefined;
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
const {
|
|
2
|
+
combineParams,
|
|
3
|
+
getTime,
|
|
4
|
+
} = require('../util');
|
|
5
|
+
|
|
6
|
+
function YouTube() {
|
|
7
|
+
this.provider = 'youtube';
|
|
8
|
+
this.alternatives = ['youtu', 'ytimg'];
|
|
9
|
+
this.defaultFormat = 'long';
|
|
10
|
+
this.formats = {
|
|
11
|
+
short: this.createShortUrl,
|
|
12
|
+
long: this.createLongUrl,
|
|
13
|
+
embed: this.createEmbedUrl,
|
|
14
|
+
shortImage: this.createShortImageUrl,
|
|
15
|
+
longImage: this.createLongImageUrl,
|
|
16
|
+
};
|
|
17
|
+
this.imageQualities = {
|
|
18
|
+
'0': '0',
|
|
19
|
+
'1': '1',
|
|
20
|
+
'2': '2',
|
|
21
|
+
'3': '3',
|
|
22
|
+
DEFAULT: 'default',
|
|
23
|
+
HQDEFAULT: 'hqdefault',
|
|
24
|
+
SDDEFAULT: 'sddefault',
|
|
25
|
+
MQDEFAULT: 'mqdefault',
|
|
26
|
+
MAXRESDEFAULT: 'maxresdefault',
|
|
27
|
+
};
|
|
28
|
+
this.defaultImageQuality = this.imageQualities.HQDEFAULT;
|
|
29
|
+
this.mediaTypes = {
|
|
30
|
+
VIDEO: 'video',
|
|
31
|
+
PLAYLIST: 'playlist',
|
|
32
|
+
SHARE: 'share',
|
|
33
|
+
CHANNEL: 'channel',
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
module.exports = YouTube;
|
|
38
|
+
|
|
39
|
+
YouTube.prototype.parseVideoUrl = function(url) {
|
|
40
|
+
var match = url.match(
|
|
41
|
+
/(?:(?:v|vi|be|videos|embed)\/(?!videoseries)|(?:v|ci)=)([\w-]{11})/i
|
|
42
|
+
);
|
|
43
|
+
return match ? match[1] : undefined;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
YouTube.prototype.parseChannelUrl = function(url) {
|
|
47
|
+
// Match an opaque channel ID
|
|
48
|
+
var match = url.match(/\/channel\/([\w-]+)/);
|
|
49
|
+
if (match) {
|
|
50
|
+
return { id: match[1], mediaType: this.mediaTypes.CHANNEL };
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Match a vanity channel name or a user name. User urls are deprecated and
|
|
54
|
+
// currently redirect to the channel of that same name.
|
|
55
|
+
match = url.match(/\/(?:c|user)\/([\w-]+)/);
|
|
56
|
+
if (match) {
|
|
57
|
+
return { name: match[1], mediaType: this.mediaTypes.CHANNEL };
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
YouTube.prototype.parseParameters = function(params, result) {
|
|
62
|
+
if (params.start || params.t) {
|
|
63
|
+
params.start = getTime(params.start || params.t);
|
|
64
|
+
delete params.t;
|
|
65
|
+
}
|
|
66
|
+
if (params.v === result.id) {
|
|
67
|
+
delete params.v;
|
|
68
|
+
}
|
|
69
|
+
if (params.list === result.id) {
|
|
70
|
+
delete params.list;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return params;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
YouTube.prototype.parseMediaType = function(result) {
|
|
77
|
+
if (result.params.list) {
|
|
78
|
+
result.list = result.params.list;
|
|
79
|
+
delete result.params.list;
|
|
80
|
+
}
|
|
81
|
+
if (result.id && !result.params.ci) {
|
|
82
|
+
result.mediaType = this.mediaTypes.VIDEO;
|
|
83
|
+
} else if (result.list) {
|
|
84
|
+
delete result.id;
|
|
85
|
+
result.mediaType = this.mediaTypes.PLAYLIST;
|
|
86
|
+
} else if (result.params.ci) {
|
|
87
|
+
delete result.params.ci;
|
|
88
|
+
result.mediaType = this.mediaTypes.SHARE;
|
|
89
|
+
} else {
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
return result;
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
YouTube.prototype.parse = function(url, params) {
|
|
96
|
+
var channelResult = this.parseChannelUrl(url);
|
|
97
|
+
if (channelResult) {
|
|
98
|
+
return channelResult;
|
|
99
|
+
} else {
|
|
100
|
+
var result = {
|
|
101
|
+
params: params,
|
|
102
|
+
id: this.parseVideoUrl(url),
|
|
103
|
+
};
|
|
104
|
+
result.params = this.parseParameters(params, result);
|
|
105
|
+
result = this.parseMediaType(result);
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
YouTube.prototype.createShortUrl = function(vi, params) {
|
|
111
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
112
|
+
return undefined;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
var url = 'https://youtu.be/' + vi.id;
|
|
116
|
+
if (params.start) {
|
|
117
|
+
url += '#t=' + params.start;
|
|
118
|
+
}
|
|
119
|
+
return url;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
YouTube.prototype.createLongUrl = function(vi, params) {
|
|
123
|
+
var url = '';
|
|
124
|
+
var startTime = params.start;
|
|
125
|
+
delete params.start;
|
|
126
|
+
|
|
127
|
+
if (vi.mediaType === this.mediaTypes.CHANNEL) {
|
|
128
|
+
if (vi.id) {
|
|
129
|
+
url += 'https://www.youtube.com/channel/' + vi.id;
|
|
130
|
+
} else if (vi.name) {
|
|
131
|
+
url += 'https://www.youtube.com/c/' + vi.name;
|
|
132
|
+
} else {
|
|
133
|
+
return undefined;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
else if (vi.mediaType === this.mediaTypes.PLAYLIST && vi.list) {
|
|
137
|
+
params.feature = 'share';
|
|
138
|
+
url += 'https://www.youtube.com/playlist';
|
|
139
|
+
}
|
|
140
|
+
else if (vi.mediaType === this.mediaTypes.VIDEO && vi.id) {
|
|
141
|
+
params.v = vi.id;
|
|
142
|
+
url += 'https://www.youtube.com/watch';
|
|
143
|
+
}
|
|
144
|
+
else if (vi.mediaType === this.mediaTypes.SHARE && vi.id) {
|
|
145
|
+
params.ci = vi.id;
|
|
146
|
+
url += 'https://www.youtube.com/shared';
|
|
147
|
+
} else {
|
|
148
|
+
return undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (vi.list) {
|
|
152
|
+
params.list = vi.list;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
url += combineParams(params);
|
|
156
|
+
|
|
157
|
+
if (vi.mediaType !== this.mediaTypes.PLAYLIST && startTime) {
|
|
158
|
+
url += '#t=' + startTime;
|
|
159
|
+
}
|
|
160
|
+
return url;
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
YouTube.prototype.createEmbedUrl = function(vi, params) {
|
|
164
|
+
var url = 'https://www.youtube.com/embed';
|
|
165
|
+
|
|
166
|
+
if (vi.mediaType === this.mediaTypes.PLAYLIST && vi.list) {
|
|
167
|
+
params.listType = 'playlist';
|
|
168
|
+
} else if (vi.mediaType === this.mediaTypes.VIDEO && vi.id) {
|
|
169
|
+
url += '/' + vi.id;
|
|
170
|
+
//loop hack
|
|
171
|
+
if (params.loop === '1') {
|
|
172
|
+
params.playlist = vi.id;
|
|
173
|
+
}
|
|
174
|
+
} else {
|
|
175
|
+
return undefined;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (vi.list) {
|
|
179
|
+
params.list = vi.list;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
url += combineParams(params);
|
|
183
|
+
|
|
184
|
+
return url;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
YouTube.prototype.createImageUrl = function(baseUrl, vi, params) {
|
|
188
|
+
if (!vi.id || vi.mediaType !== this.mediaTypes.VIDEO) {
|
|
189
|
+
return undefined;
|
|
190
|
+
}
|
|
191
|
+
var url = baseUrl + vi.id + '/';
|
|
192
|
+
var quality = params.imageQuality || this.defaultImageQuality;
|
|
193
|
+
|
|
194
|
+
return url + quality + '.jpg';
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
YouTube.prototype.createShortImageUrl = function(vi, params) {
|
|
198
|
+
return this.createImageUrl('https://i.ytimg.com/vi/', vi, params);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
YouTube.prototype.createLongImageUrl = function(vi, params) {
|
|
202
|
+
return this.createImageUrl('https://img.youtube.com/vi/', vi, params);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
require('../base').bind(new YouTube());
|
package/lib/testUrls.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
exports.testUrls = (parser, obj) => {
|
|
2
|
+
const { urls, videoInfo, formats } = obj;
|
|
3
|
+
const { parse, create } = parser;
|
|
4
|
+
for (const url of urls) {
|
|
5
|
+
expect(parse(url), 'Parse Url: ' + url).toEqual(videoInfo);
|
|
6
|
+
}
|
|
7
|
+
for (const format of Object.keys(formats)) {
|
|
8
|
+
const createdUrl = create({ videoInfo, format, params: videoInfo.params });
|
|
9
|
+
expect(createdUrl, 'Created Url: ' + createdUrl).toBe(formats[format]);
|
|
10
|
+
}
|
|
11
|
+
};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import Provider from './provider/base-provider';
|
|
2
|
+
|
|
3
|
+
export interface Options {
|
|
4
|
+
videoInfo: VideoInfo;
|
|
5
|
+
params?: 'internal' | Record<string, any>;
|
|
6
|
+
format?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface VideoInfo<UrlParameters = Record<string, any>, MediaTypes = string> {
|
|
10
|
+
provider?: string;
|
|
11
|
+
id: string;
|
|
12
|
+
mediaType?: MediaTypes;
|
|
13
|
+
params?: UrlParameters;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export default class UrlParser {
|
|
17
|
+
plugins: Record<string, Provider>;
|
|
18
|
+
|
|
19
|
+
parseProvider(url: string): string | undefined;
|
|
20
|
+
parse(url: string): VideoInfo | undefined;
|
|
21
|
+
bind(plugin: Provider): void;
|
|
22
|
+
create(op: Options): string | undefined;
|
|
23
|
+
}
|
package/lib/urlParser.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
const {
|
|
2
|
+
getQueryParams,
|
|
3
|
+
} = require('./util');
|
|
4
|
+
|
|
5
|
+
function UrlParser() {
|
|
6
|
+
for (const key of [
|
|
7
|
+
'parseProvider',
|
|
8
|
+
'parse',
|
|
9
|
+
'bind',
|
|
10
|
+
'create',
|
|
11
|
+
]) {
|
|
12
|
+
this[key] = this[key].bind(this);
|
|
13
|
+
}
|
|
14
|
+
this.plugins = {};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
module.exports = UrlParser;
|
|
18
|
+
|
|
19
|
+
UrlParser.prototype.parseProvider = function(url) {
|
|
20
|
+
var match = url.match(
|
|
21
|
+
/(?:(?:https?:)?\/\/)?(?:[^.]+\.)?(\w+)\./i
|
|
22
|
+
);
|
|
23
|
+
return match ? match[1] : undefined;
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
UrlParser.prototype.parse = function(url) {
|
|
27
|
+
if (typeof url === 'undefined') {
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
var provider = this.parseProvider(url);
|
|
31
|
+
var result;
|
|
32
|
+
var plugin = this.plugins[provider];
|
|
33
|
+
if (!provider || !plugin || !plugin.parse) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
result = plugin.parse.call(
|
|
37
|
+
plugin, url, getQueryParams(url)
|
|
38
|
+
);
|
|
39
|
+
if (result) {
|
|
40
|
+
result = removeEmptyParameters(result);
|
|
41
|
+
result.provider = plugin.provider;
|
|
42
|
+
}
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
UrlParser.prototype.bind = function(plugin) {
|
|
47
|
+
this.plugins[plugin.provider] = plugin;
|
|
48
|
+
if (plugin.alternatives) {
|
|
49
|
+
for (var i = 0; i < plugin.alternatives.length; i += 1) {
|
|
50
|
+
this.plugins[plugin.alternatives[i]] = plugin;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
UrlParser.prototype.create = function(op) {
|
|
56
|
+
if (typeof (op) !== 'object' || typeof (op.videoInfo) !== 'object') {
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
var vi = op.videoInfo;
|
|
61
|
+
var params = op.params;
|
|
62
|
+
var plugin = this.plugins[vi.provider];
|
|
63
|
+
|
|
64
|
+
params = (params === 'internal') ? vi.params : params || {};
|
|
65
|
+
|
|
66
|
+
if (plugin) {
|
|
67
|
+
op.format = op.format || plugin.defaultFormat;
|
|
68
|
+
// eslint-disable-next-line no-prototype-builtins
|
|
69
|
+
if (plugin.formats.hasOwnProperty(op.format)) {
|
|
70
|
+
return plugin.formats[op.format].apply(plugin, [vi, Object.assign({}, params)]);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return undefined;
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
function removeEmptyParameters(result) {
|
|
77
|
+
if (result.params && Object.keys(result.params).length === 0) {
|
|
78
|
+
delete result.params;
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|