Skip to content

Commit

Permalink
Finish #3123: "reddit" media host, for image posts that link to comme…
Browse files Browse the repository at this point in the history
…nts page (#3156)

* don't expando pixel.redditmedia.com (promoted post clickthrough urls)

* ignore nyc outut

* utils.getPostMetadata

fetch API response for (many batched) reddit posts

* comments regex returns post ID

* show expando on post's original url if post links to comments+preview

* showImages.options.expandoCommentRedirects to control handling of posts redirecting to comments
either: ignore them, hit the api to get the expando, or hit the api to get the expando and also change the link to point to said expando's image
  • Loading branch information
erikdesjardins committed Jul 15, 2016
1 parent f61d0da commit 2c5aaee
Show file tree
Hide file tree
Showing 7 changed files with 100 additions and 32 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,4 @@ $RECYCLE.BIN/
## IntelliJ
.idea
*.iml
.nyc_output
2 changes: 1 addition & 1 deletion lib/modules/hosts/redditmedia.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export default {
name: 'redditmedia',
domains: ['redditmedia.com'],
attribution: false,
detect: () => true,
detect: ({ hostname }) => hostname !== 'pixel.redditmedia.com',
handleLink(href) {
if (getUrlParams(href).fm === 'mp4') {
return {
Expand Down
92 changes: 69 additions & 23 deletions lib/modules/showImages.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
expandos,
primaryExpandos,
Thing,
getPostMetadata,
addCSS,
batch,
CreateElement,
Expand All @@ -33,6 +34,7 @@ import {
objectValidator,
waitForEvent,
watchForElement,
regexes,
} from '../utils';
import { addURLToHistory, ajax, isPrivateBrowsing, openNewTab } from '../environment';
import * as SettingsNavigation from './settingsNavigation';
Expand Down Expand Up @@ -249,6 +251,21 @@ module.options = {
value: true,
description: 'Show the site logo and name after embedded content.',
},
expandoCommentRedirects: {
type: 'enum',
value: 'expando',
values: [{
name: 'Do nothing',
value: 'nothing',
}, {
name: 'Create expandos',
value: 'expando',
}, {
name: 'Create expandos, redirect the link back to the image',
value: 'rewrite',
}],
description: 'How should RES handle posts where the link is redirected to the comments page with preview expanded?',
},
showVideoControls: {
type: 'boolean',
value: true,
Expand Down Expand Up @@ -621,38 +638,64 @@ async function convertGifToVideo(options) {
}
}

function getMediaInfo(mediaLink) {
async function resolveMediaUrl(element, thing) {
if (module.options.expandoCommentRedirects.value === 'nothing') {
return element;
}

if (element.classList.contains('title')) {
const dataUrl = thing.$thing.data('url');
const fullDataUrl = dataUrl && new URL(dataUrl, location);
if (fullDataUrl && fullDataUrl.href !== thing.getCommentsLink().href) {
return fullDataUrl;
}

if (element.hostname === location.hostname) {
const [, , id] = regexes.comments.exec(element.pathname);
const { url } = await getPostMetadata({ id });

if (module.options.expandoCommentRedirects.value === 'rewrite') {
element.href = url;
}

return new URL(url, location);
}
}

return element;
}

function getMediaInfo(element, mediaUrl) {
const matchingHosts = _.compact([
domainModuleMap[getMainDomainComponent(mediaLink.hostname)],
domainModuleMap[getMainDomainComponent(mediaUrl.hostname)],
siteModules.default,
siteModules.defaultVideo,
siteModules.defaultAudio,
]);

for (const siteModule of matchingHosts) {
const detectResult = siteModule.detect(mediaLink);
if (detectResult) return { detectResult, siteModule, mediaLink, href: mediaLink.href };
const detectResult = siteModule.detect(mediaUrl);
if (detectResult) return { detectResult, siteModule, element, href: mediaUrl.href };
}
}

// @type {WeakMap.<mediaLink, boolean|Expando>}
// @type {WeakMap.<element, boolean|Expando>}
const scannedLinks = new WeakMap();
export const getLinkExpando = link => {
const expando = scannedLinks.get(link);
if (expando instanceof Expando) return expando;
};

function checkElementForMedia(mediaLink) {
if (scannedLinks.has(mediaLink)) return;
else scannedLinks.set(mediaLink, true);
async function checkElementForMedia(element) {
if (scannedLinks.has(element)) return;
else scannedLinks.set(element, true);

const thing = new Thing(mediaLink);
const thing = new Thing(element);
if (!thing.element) return;

const inText = !!$(mediaLink).closest('.md, .search-result-footer')[0];
const inText = !!$(element).closest('.md, .search-result-footer')[0];
const entryExpando = !inText && thing.getEntryExpando();
const nativeExpando = entryExpando instanceof Expando ? null : entryExpando;
const mediaInfo = getMediaInfo(mediaLink);

if (module.options.hideNSFW.value && thing.isNSFW()) {
if (nativeExpando) nativeExpando.detach();
Expand All @@ -661,27 +704,30 @@ function checkElementForMedia(mediaLink) {
}

if (nativeExpando) {
trackNativeExpando(nativeExpando, mediaLink);
trackNativeExpando(nativeExpando, element);

if (nativeExpando.open) {
console.log('Native expando has already been opened; skipping.', mediaLink.href);
console.log('Native expando has already been opened; skipping.', element.href);
return;
}

if (mediaInfo) nativeExpando.detach();
}

const mediaUrl = await resolveMediaUrl(element, thing);
const mediaInfo = getMediaInfo(element, mediaUrl);

if (!mediaInfo) return;

if (nativeExpando) nativeExpando.detach();

const expando = new Expando(inText);
expandos.set(expando.button, expando);
scannedLinks.set(mediaLink, expando);
scannedLinks.set(element, expando);

if (!inText && thing.getTitleElement()) {
$(expando.button).insertAfter(mediaLink.parentElement);
$(expando.button).insertAfter(element.parentElement);
thing.entry.appendChild(expando.box);
} else {
$(mediaLink).add($(mediaLink).next('.keyNavAnnotation')).last()
$(element).add($(element).next('.keyNavAnnotation')).last()
.after(expando.box)
.after(expando.button);
}
Expand All @@ -701,7 +747,7 @@ function checkElementForMedia(mediaLink) {

if (nativeExpando) nativeExpando.reattach();
expando.destroy();
scannedLinks.set(mediaLink, true);
scannedLinks.set(element, true);
});
};

Expand Down Expand Up @@ -757,7 +803,7 @@ async function completeExpando(expando, thing, mediaInfo) {
updateAutoExpandCount();
}

const retrieveExpandoOptions = _.memoize(async (thing, { siteModule, detectResult, mediaLink, href }) => {
const retrieveExpandoOptions = _.memoize(async (thing, { siteModule, detectResult, element, href }) => {
let mediaOptions = await siteModule.handleLink(href, detectResult);

if (module.options.convertGifstoGfycat.value &&
Expand All @@ -782,7 +828,7 @@ const retrieveExpandoOptions = _.memoize(async (thing, { siteModule, detectResul
...mediaOptions,
};

const trackLoad = _.once(() => trackMediaLoad(mediaLink));
const trackLoad = _.once(() => trackMediaLoad(element));

return {
href, // Since mediaOptions.href may be overwritten
Expand Down Expand Up @@ -811,11 +857,11 @@ function updateParentHeight(e) {
}
}

function trackNativeExpando(expando, mediaLink) {
function trackNativeExpando(expando, element) {
// only track media
if (expando.button.classList.contains('selftext')) return;

const trackLoad = _.once(() => trackMediaLoad(mediaLink));
const trackLoad = _.once(() => trackMediaLoad(element));

if (expando.open) trackLoad();
else expando.button.addEventListener('click', trackLoad);
Expand Down
14 changes: 7 additions & 7 deletions lib/utils/__tests__/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,13 @@ test('frontpage', regexMatches, regexes.frontpage, [
]);

test('comments regex', regexMatches, regexes.comments, [
['/comments/', undefined],
['/comments', undefined],
['/r/aww/comments/4ooe2m/', 'aww'],
['/r/aww/comments/4ooe2m', 'aww'],
['/r/reddit.com/comments', 'reddit.com'],
['/comments/4ooe2m/', undefined],
['/comments/4ooe2m', undefined],
['/comments/', undefined, undefined],
['/comments', undefined, undefined],
['/r/aww/comments/4ooe2m/', 'aww', '4ooe2m'],
['/r/aww/comments/4ooe2m', 'aww', '4ooe2m'],
['/r/reddit.com/comments', 'reddit.com', undefined],
['/comments/4ooe2m/', undefined, '4ooe2m'],
['/comments/4ooe2m', undefined, '4ooe2m'],
]);

test('inbox regex', regexMatches, regexes.inbox, [
Expand Down
4 changes: 4 additions & 0 deletions lib/utils/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export Cache from './Cache';

export Thing from './Thing';

export {
getPostMetadata,
} from './thingMetadata';

export {
asyncFilter,
asyncFind,
Expand Down
2 changes: 1 addition & 1 deletion lib/utils/location.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export function matchesPageLocation(includes = [], excludes = []) {
/* eslint-disable key-spacing */
export const regexes = {
frontpage: /^\/(?:hot|new|rising|controversial|top)?(?:\/|$)/i,
comments: /^\/(?:r\/([\w\.]+)\/)?comments(?:\/|$)/i,
comments: /^\/(?:r\/([\w\.]+)\/)?comments(?:\/([a-z0-9]+))?(?:\/|$)/i,
inbox: /^\/message(?:\/|$)/i,
profile: /^\/user\/([\w\-]+)(?:\/(?!m\/)|$)/i,
submit: /^\/(?:r\/([\w\.\+]+)\/)?submit(?:\/|$)/i,
Expand Down
17 changes: 17 additions & 0 deletions lib/utils/thingMetadata.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { ajax } from '../environment';
import { batch } from './async';

export const getPostMetadata = batch(async requests => {
const byId = requests
.map(r => r.id)
.map(id => `t3_${id}`)
.join(',');

const { data: { children } } = await ajax({
url: `/by_id/${byId}.json`,
data: { limit: 100 },
type: 'json',
});

return children.map(c => c.data);
}, { size: 100 });

0 comments on commit 2c5aaee

Please sign in to comment.