Skip to content

Commit 4a144cb

Browse files
committed
twitter: add an option to disable (broken) Twitter timeline
1 parent 9212b88 commit 4a144cb

File tree

1 file changed

+105
-85
lines changed

1 file changed

+105
-85
lines changed

plugins/domains/twitter.com/twitter.timelines.js

Lines changed: 105 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ export default {
22

33
// Embedded Like, Collection, and Moment Timelines are now retired.
44
// https://twittercommunity.com/t/removing-support-for-embedded-like-collection-and-moment-timelines/150313
5+
6+
// Embedded user timelines are broken (429) as of May 2025
7+
//
58
re: [
69
/^https?:\/\/(?:twitter|x)\.com\/(\w+)\/lists?\/(\d+)/i,
710
/^https?:\/\/(?:twitter|x)\.com\/(\w+)\/?(?:\?.*)?$/i,
@@ -24,112 +27,129 @@ export default {
2427

2528
getLink: function(url, oembed, twitter_og, options) {
2629

27-
var html = oembed.html;
28-
29-
var locale = options.getProviderOptions('locale');
30-
var locale_RE = /^\w{2,3}(?:(?:\_|\-)\w{2,3})?$/i;
31-
if (locale && locale_RE.test(locale)) {
32-
if (!/^zh\-/i.test(locale)) {
33-
locale = locale.replace(/\-.+$/i, '');
34-
}
35-
html = html.replace(/<a class="twitter\-timeline"( data\-lang="\w+(?:(?:\_|\-)\w+)?")?/, '<a class="twitter-timeline" data-lang="' + locale + '"');
36-
}
30+
var links = [];
31+
var enable_timeline = options.getRequestOptions('twitter.timeline', true);
3732

38-
var width = options.getRequestOptions('twitter.maxwidth',
39-
(/data\-width=\"(\d+)\"/i.test(html) && html.match(/data\-width=\"(\d+)\"/i)[1])
40-
|| '');
33+
if (oembed.html && enable_timeline) {
34+
var html = oembed.html;
4135

42-
if (/^\d+$/.test(width)) {
43-
if (/data\-width=\"(\d+)\"/i.test(html)) {
44-
html = html.replace(/data\-width=\"(\d+)\"/i, `data-width="${width}"`);
45-
} else {
46-
html = html.replace('<a class="twitter-timeline"', `<a class="twitter-timeline" data-width="${width}"`);
36+
var locale = options.getProviderOptions('locale');
37+
var locale_RE = /^\w{2,3}(?:(?:\_|\-)\w{2,3})?$/i;
38+
if (locale && locale_RE.test(locale)) {
39+
if (!/^zh\-/i.test(locale)) {
40+
locale = locale.replace(/\-.+$/i, '');
41+
}
42+
html = html.replace(/<a class="twitter\-timeline"( data\-lang="\w+(?:(?:\_|\-)\w+)?")?/, '<a class="twitter-timeline" data-lang="' + locale + '"');
4743
}
48-
} else {
49-
html = html.replace(/data\-width=\"\d+\"\s?/i, '');
50-
width = ''; // Includes input validation
51-
}
5244

53-
// `data-height` works only if there's no `data-limit`.
54-
var height = options.getRequestOptions('twitter.height',
55-
(/data\-height=\"(\d+)\"/i.test(html) && html.match(/data\-height=\"(\d+)\"/i)[1])
56-
|| '');
45+
var width = options.getRequestOptions('twitter.maxwidth',
46+
(/data\-width=\"(\d+)\"/i.test(html) && html.match(/data\-width=\"(\d+)\"/i)[1])
47+
|| '');
5748

58-
if (/^\d+$/.test(height)) {
59-
if (/data\-height=\"(\d+)\"/i.test(html)) {
60-
html = html.replace(/data\-height=\"(\d+)\"/i, `data-height="${height}"`);
49+
if (/^\d+$/.test(width)) {
50+
if (/data\-width=\"(\d+)\"/i.test(html)) {
51+
html = html.replace(/data\-width=\"(\d+)\"/i, `data-width="${width}"`);
52+
} else {
53+
html = html.replace('<a class="twitter-timeline"', `<a class="twitter-timeline" data-width="${width}"`);
54+
}
6155
} else {
62-
html = html.replace('<a class="twitter-timeline"', `<a class="twitter-timeline" data-height="${height}"`);
56+
html = html.replace(/data\-width=\"\d+\"\s?/i, '');
57+
width = ''; // Includes input validation
6358
}
64-
} else {
65-
html = html.replace(/data\-height=\"\d+\"\s?/i, '');
66-
height = ''; // Includes input validation
67-
}
6859

69-
if (options.getProviderOptions('twitter.center', true) && /data\-width=\"\d+\"/i.test(html)) {
70-
html = '<div align="center">' + html + '</div>';
71-
}
60+
// `data-height` works only if there's no `data-limit`.
61+
var height = options.getRequestOptions('twitter.height',
62+
(/data\-height=\"(\d+)\"/i.test(html) && html.match(/data\-height=\"(\d+)\"/i)[1])
63+
|| '');
64+
65+
if (/^\d+$/.test(height)) {
66+
if (/data\-height=\"(\d+)\"/i.test(html)) {
67+
html = html.replace(/data\-height=\"(\d+)\"/i, `data-height="${height}"`);
68+
} else {
69+
html = html.replace('<a class="twitter-timeline"', `<a class="twitter-timeline" data-height="${height}"`);
70+
}
71+
} else {
72+
html = html.replace(/data\-height=\"\d+\"\s?/i, '');
73+
height = ''; // Includes input validation
74+
}
7275

73-
var limit = options.getRequestOptions('twitter.limit',
74-
(/data\-(?:tweet\-)?limit=\"(\d+)\"/i.test(html) && html.match(/data\-(?:tweet\-)?limit=\"(\d+)\"/i)[1])
75-
|| 20);
76+
if (options.getProviderOptions('twitter.center', true) && /data\-width=\"\d+\"/i.test(html)) {
77+
html = '<div align="center">' + html + '</div>';
78+
}
7679

77-
if (/data\-(?:tweet\-)?limit=\"(\d+)\"/.test(html)) {
78-
html = html.replace(/data\-(?:tweet\-)?limit=\"\d+\"/, '');
79-
}
80+
var limit = options.getRequestOptions('twitter.limit',
81+
(/data\-(?:tweet\-)?limit=\"(\d+)\"/i.test(html) && html.match(/data\-(?:tweet\-)?limit=\"(\d+)\"/i)[1])
82+
|| 20);
8083

81-
if (height) {
82-
limit = 20; // `data-height` works only if there's no `data-limit`. Let's give it priority.
83-
}
84+
if (/data\-(?:tweet\-)?limit=\"(\d+)\"/.test(html)) {
85+
html = html.replace(/data\-(?:tweet\-)?limit=\"\d+\"/, '');
86+
}
8487

85-
if (limit !== 20) {
86-
html = html.replace(/href="/, 'data-tweet-limit="' + limit + '" href="');
87-
}
88+
if (height) {
89+
limit = 20; // `data-height` works only if there's no `data-limit`. Let's give it priority.
90+
}
8891

89-
var theme = options.getRequestOptions('players.theme', '');
90-
if (theme === 'dark' && !/data\-theme=\"dark\"/.test(html)) {
91-
html = html.replace(/href="/, 'data-theme="dark" href="');
92-
}
92+
if (limit !== 20) {
93+
html = html.replace(/href="/, 'data-tweet-limit="' + limit + '" href="');
94+
}
9395

96+
var theme = options.getRequestOptions('players.theme', '');
97+
if (theme === 'dark' && !/data\-theme=\"dark\"/.test(html)) {
98+
html = html.replace(/href="/, 'data-theme="dark" href="');
99+
}
94100

95-
var links = [{
96-
html: html,
97-
rel: [CONFIG.R.reader, CONFIG.R.ssl, CONFIG.R.inline],
98-
type: CONFIG.T.text_html,
99-
options: {
100-
limit: {
101-
label: 'Include up to 20 tweets',
102-
value: limit,
103-
range: {
104-
max: 20,
105-
min: 1
106-
}
107-
},
108-
theme: {
109-
value: theme,
110-
values: {
111-
dark: "Use dark theme"
101+
links.push({
102+
html: html,
103+
rel: [CONFIG.R.reader, CONFIG.R.ssl, CONFIG.R.inline],
104+
type: CONFIG.T.text_html,
105+
options: {
106+
timeline: {
107+
label: 'Embed as timeline',
108+
value: true
109+
},
110+
limit: {
111+
label: 'Include up to 20 tweets',
112+
value: limit,
113+
range: {
114+
max: 20,
115+
min: 1
116+
}
117+
},
118+
theme: {
119+
value: theme,
120+
values: {
121+
dark: "Use dark theme"
122+
}
123+
},
124+
maxwidth: {
125+
value: width || '',
126+
label: CONFIG.L.width,
127+
placeholder: 'e.g. 550, in px'
128+
},
129+
height: {
130+
label: CONFIG.L.height,
131+
value: height,
132+
placeholder: 'in px. Overrides # of tweets.'
112133
}
113-
},
114-
maxwidth: {
115-
value: width || '',
116-
label: CONFIG.L.width,
117-
placeholder: 'e.g. 550, in px'
118-
},
119-
height: {
120-
label: CONFIG.L.height,
121-
value: height,
122-
placeholder: 'in px. Overrides # of tweets.'
123-
}
124-
}
125-
}];
134+
}
135+
})
136+
}
126137

127138
if (twitter_og.image) {
128-
links.push({
139+
var thumbnail = {
129140
href: twitter_og.image.url || twitter_og.image.src || twitter_og.image,
130141
type: CONFIG.T.image,
131142
rel: CONFIG.R.thumbnail
132-
});
143+
};
144+
if (!enable_timeline) {
145+
thumbnail.options = {
146+
timeline: {
147+
label: 'Embed as timeline',
148+
value: false
149+
}
150+
}
151+
}
152+
links.push(thumbnail);
133153
}
134154

135155
return links;

0 commit comments

Comments
 (0)