From 3a0f94a230f4b826806d959714492320ca2b9866 Mon Sep 17 00:00:00 2001 From: SirStendec Date: Sun, 2 Sep 2018 13:30:51 -0400 Subject: [PATCH] 4.0.0-rc12.18 * Fixed: Force Apollo queries to reload if there is missing data in the cache. This should fix the loading errors. * Fixed: Use `Tier 1`, `Tier 2`, `Tier 3`, etc. in the emote menu when the price is not available for a subscription product. --- src/main.js | 2 +- .../modules/chat/emote_menu.jsx | 8 +- .../modules/directory/followed_index.gql | 10 ++ .../modules/directory/following.jsx | 8 + .../modules/directory/game.jsx | 2 +- .../modules/directory/index.jsx | 4 +- .../directory/recommended_channels.gql | 12 ++ src/utilities/compat/apollo.js | 142 ++++++++---------- 8 files changed, 105 insertions(+), 83 deletions(-) create mode 100644 src/sites/twitch-twilight/modules/directory/recommended_channels.gql diff --git a/src/main.js b/src/main.js index 2158666d..5f1bcd1f 100644 --- a/src/main.js +++ b/src/main.js @@ -100,7 +100,7 @@ class FrankerFaceZ extends Module { FrankerFaceZ.Logger = Logger; const VER = FrankerFaceZ.version_info = { - major: 4, minor: 0, revision: 0, extra: '-rc12.17', + major: 4, minor: 0, revision: 0, extra: '-rc12.18', commit: __git_commit__, build: __webpack_hash__, toString: () => diff --git a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx index ccf0b487..bed63076 100644 --- a/src/sites/twitch-twilight/modules/chat/emote_menu.jsx +++ b/src/sites/twitch-twilight/modules/chat/emote_menu.jsx @@ -13,6 +13,12 @@ import Module from 'utilities/module'; import SUB_STATUS from './sub_status.gql'; +const TIERS = { + 1000: 'Tier 1', + 2000: 'Tier 2', + 3000: 'Tier 3' +}; + const TONE_EMOJI = [ 'the_horns', 'raised_back_of_hand', @@ -1320,7 +1326,7 @@ export default class EmoteMenu extends Module { locks[set_id] = { set_id, id: product.id, - price: product.price, + price: product.price || TIERS[product.tier], url: product.url, emotes: lock_set = new Set(emotes.map(e => e.id)) } diff --git a/src/sites/twitch-twilight/modules/directory/followed_index.gql b/src/sites/twitch-twilight/modules/directory/followed_index.gql index 0dd90430..7d65d87f 100644 --- a/src/sites/twitch-twilight/modules/directory/followed_index.gql +++ b/src/sites/twitch-twilight/modules/directory/followed_index.gql @@ -7,5 +7,15 @@ query { } } } + followedHosts { + nodes { + profileImageURL(width: 50) + hosting { + stream { + createdAt + } + } + } + } } } \ No newline at end of file diff --git a/src/sites/twitch-twilight/modules/directory/following.jsx b/src/sites/twitch-twilight/modules/directory/following.jsx index 026a32a7..9b1f4228 100644 --- a/src/sites/twitch-twilight/modules/directory/following.jsx +++ b/src/sites/twitch-twilight/modules/directory/following.jsx @@ -15,6 +15,7 @@ import FOLLOWED_HOSTS from './followed_hosts.gql'; import FOLLOWED_CHANNELS from './followed_channels.gql'; import FOLLOWED_LIVE from './followed_live.gql'; import SUBSCRIBED_CHANNELS from './sidenav_subscribed.gql'; +import RECOMMENDED_CHANNELS from './recommended_channels.gql'; export default class Following extends SiteModule { constructor(...args) { @@ -66,6 +67,7 @@ export default class Following extends SiteModule { this.apollo.registerModifier('FollowedChannels_RENAME2', FOLLOWED_CHANNELS); this.apollo.registerModifier('SideNav_SubscribedChannels', SUBSCRIBED_CHANNELS); + this.apollo.registerModifier('RecommendedChannels', RECOMMENDED_CHANNELS); this.apollo.registerModifier('FollowedIndex_CurrentUser', FOLLOWED_INDEX); this.apollo.registerModifier('FollowingLive_CurrentUser', FOLLOWED_LIVE); @@ -73,6 +75,7 @@ export default class Following extends SiteModule { this.apollo.registerModifier('FollowedChannels_RENAME2', res => this.modifyLiveUsers(res), false); this.apollo.registerModifier('SideNav_SubscribedChannels', res => this.modifyLiveUsers(res, 'subscribedChannels'), false); + this.apollo.registerModifier('RecommendedChannels', res => this.modifyLiveUsers(res, 'recommendations.liveRecommendations'), false); this.apollo.registerModifier('FollowingLive_CurrentUser', res => this.modifyLiveUsers(res), false); this.apollo.registerModifier('FollowingHosts_CurrentUser', res => this.modifyLiveHosts(res), false); @@ -159,6 +162,11 @@ export default class Following extends SiteModule { 'data.currentUser.subscribedChannels.edges.0.node.stream.createdAt' ); + this.apollo.ensureQuery( + 'RecommendedChannels', + 'data.currentUser.recommendations.liveRecommendations.nodes.0.createdAt' + ); + if ( this.router.current_name !== 'dir-following' ) return; diff --git a/src/sites/twitch-twilight/modules/directory/game.jsx b/src/sites/twitch-twilight/modules/directory/game.jsx index 780f3a9e..d84cca33 100644 --- a/src/sites/twitch-twilight/modules/directory/game.jsx +++ b/src/sites/twitch-twilight/modules/directory/game.jsx @@ -97,7 +97,7 @@ export default class Game extends SiteModule { ['dir-game-index', 'dir-community', 'dir-game-videos', 'dir-game-clips', 'dir-game-details'] ); - this.apollo.registerModifier('GamePage_Game_RENAME2', GAME_QUERY); + this.apollo.registerModifier('DirectoryPage_Game', GAME_QUERY); } onEnable() { diff --git a/src/sites/twitch-twilight/modules/directory/index.jsx b/src/sites/twitch-twilight/modules/directory/index.jsx index e53d15d8..aad6cb19 100644 --- a/src/sites/twitch-twilight/modules/directory/index.jsx +++ b/src/sites/twitch-twilight/modules/directory/index.jsx @@ -46,7 +46,7 @@ export default class Directory extends SiteModule { this.inject(Game); this.inject(BrowsePopular); - this.apollo.registerModifier('GamePage_Game_RENAME2', res => this.modifyStreams(res), false); + this.apollo.registerModifier('DirectoryPage_Game', res => this.modifyStreams(res), false); this.DirectoryCard = this.fine.define( 'directory-card', @@ -216,7 +216,7 @@ export default class Directory extends SiteModule { // Game Directory Channel Cards // TODO: Better query handling. this.apollo.ensureQuery( - 'GamePage_Game_RENAME2', + 'DirectoryPage_Game', 'data.directory.streams.edges.0.node.createdAt' ); diff --git a/src/sites/twitch-twilight/modules/directory/recommended_channels.gql b/src/sites/twitch-twilight/modules/directory/recommended_channels.gql new file mode 100644 index 00000000..09300ea9 --- /dev/null +++ b/src/sites/twitch-twilight/modules/directory/recommended_channels.gql @@ -0,0 +1,12 @@ +query { + currentUser { + recommendations { + liveRecommendations { + nodes { + createdAt + type + } + } + } + } +} \ No newline at end of file diff --git a/src/utilities/compat/apollo.js b/src/utilities/compat/apollo.js index 481d0882..e6ba4f16 100644 --- a/src/utilities/compat/apollo.js +++ b/src/utilities/compat/apollo.js @@ -77,6 +77,45 @@ export default class Apollo extends Module { this.hooked_query_init = false; + const t = this, + proto = this.client.queryManager.constructor.prototype, + old_qm_get = proto.getCurrentQueryResult; + + proto.getCurrentQueryResult = function(query, optimistic = true) { + const out = old_qm_get.call(this, query, optimistic); + if ( out && out.partial ) + try { + try { + const prev = query.getLastResult(), + opts = query.options; + this.dataStore.getCache().read({ + query: opts.query, + variables: opts.variables, + previousResult: prev ? prev.data : undefined, + optimistic + }); + + } catch(err) { + // If there's a missing field, and we have a lastResult, and lastResult is not loading, and lastResult is not error... + if ( err.toString().includes("Can't find field") && query.lastResult && ! query.lastResult.loading && ! query.lastError ) { + if ( Date.now() - (query._ffz_last_retry || 0) >= 120000 ) { + const raw_name = get('options.query.definitions.0.name', query), + name = raw_name && raw_name.kind === 'Name' ? raw_name.value : `#${query.queryId}`; + + t.log.info('Forcing query to refetch due to missing field:', name); + query._ffz_last_retry = Date.now(); + query.refetch(); + } + } + } + + } catch(err) { + t.log.capture(err); + } + + return out; + } + if ( this.client.queryManager.queryStore ) { const old_qm_init = this.client.queryManager.queryStore.initQuery; this.hooked_query_init = true; @@ -118,86 +157,33 @@ export default class Apollo extends Module { return forward(operation); } - const out = forward(operation); + return forward(operation).map(result => { + if ( result.extensions && result.extensions.operationName === operation.operationName ) + this.log.crumb({ + level: 'info', + category: 'gql', + message: `${operation.operationName} [${result.extensions && result.extensions.durationMilliseconds || '??'}ms]`, + data: { + variables: vars, + } + }); - if ( out.subscribe ) - return new out.constructor(observer => { - try { - out.subscribe({ - next: result => { - // Logging GQL errors is garbage. Don't do it. - /*if ( result.errors ) { - const name = operation.operationName; - if ( name && (name.includes('FFZ') || has(this.modifiers, name) || has(this.post_modifiers, name)) ) { - for(const err of result.errors) { - if ( skip_error(err) ) - continue; - - this.log.capture(new GQLError(err), { - tags: { - operation: operation.operationName - }, - extra: { - variables: vars - } - }); - } - } - }*/ - - this.log.crumb({ - level: 'info', - category: 'gql', - message: `${operation.operationName} [${result.extensions && result.extensions.durationMilliseconds || '??'}ms]`, - data: { - variables: vars, - } - }); - - try { - this.apolloPostFlight(result); - } catch(err) { - this.log.capture(err, { - tags: { - operation: operation.operationName - }, - extra: { - variables: vars - } - }); - this.log.error('Error running Post-Flight', err, result); - } - - observer.next(result); - }, - - error: err => { - observer.error(err); - }, - - complete: observer.complete.bind(observer) - }); - - } catch(err) { - this.log.capture(err, { - tags: { - operation: operation.operationName - }, - extra: { - variables: vars - } - }); - this.log.error('Link Error', err); - observer.error(err); - } - }); - - else { - // We didn't get the sort of output we expected. - this.log.info('Unexpected Link Result', out); - return out; - } + try { + this.apolloPostFlight(result); + } catch(err) { + this.log.capture(err, { + tags: { + operation: operation.operationName + }, + extra: { + variables: vars + } + }); + this.log.error('Error running Post-Flight', err, result); + } + return result; + }); }) this.old_link = this.client.link;