this.shouldShow(addon));
},
@@ -180,10 +184,8 @@ export default {
if ( value && value.length )
for(const addon of this.item.getAddons())
- if ( addon.unlisted && addon.id === value ) {
- this.unlisted.push(value);
- break;
- }
+ if ( addon.unlisted && (addon.id === value || (addon.short_name && addon.short_name.toLowerCase() === value) || (addon.name && addon.name.toLowerCase() === value)) )
+ this.unlisted.push(addon.id);
this.$refs.unlisted.value = '';
this.closeUnlisted();
diff --git a/src/modules/main_menu/components/home-page.vue b/src/modules/main_menu/components/home-page.vue
index 2547c712..c167a786 100644
--- a/src/modules/main_menu/components/home-page.vue
+++ b/src/modules/main_menu/components/home-page.vue
@@ -267,23 +267,28 @@ export default {
if ( addons )
for(const [key, addon] of Object.entries(addons)) {
const enabled = addon_module.isAddonEnabled(key),
- copy = {
- key,
- enabled,
- icon: addon.icon,
- name: addon.name,
- name_i18n: addon.name_i18n,
- updated: addon.updated,
- settings: addon.settings,
- version: addon.version
- };
+ is_new = addon.created && addon.created >= week_ago,
+ is_updated = enabled && addon.updated && addon.updated >= week_ago;
- if ( addon.created && addon.created >= week_ago )
+ if ( ! is_updated && ! (is_new && ! enabled && ! addon.unlisted) )
+ continue;
+
+ const copy = {
+ key,
+ enabled,
+ icon: addon.icon,
+ name: addon.name,
+ name_i18n: addon.name_i18n,
+ updated: addon.updated,
+ settings: addon.settings,
+ version: addon.version
+ };
+
+ if ( is_new )
new_out.push(copy);
- if ( addon.updated && addon.updated >= week_ago && enabled ) {
+ if ( is_updated )
out.push(copy);
- }
}
out.sort((a,b) => b.updated - a.updated);
diff --git a/src/sites/twitch-twilight/modules/theme/index.js b/src/sites/twitch-twilight/modules/theme/index.js
index 2d7c2a16..47d6f196 100644
--- a/src/sites/twitch-twilight/modules/theme/index.js
+++ b/src/sites/twitch-twilight/modules/theme/index.js
@@ -485,7 +485,7 @@ The CSS loaded by this setting is far too heavy and can cause performance issues
this.toggleNormalizer(chat_bits.length || bits.length);
if ( bits.length )
- this.css_tweaks.set('colors', `body {${bits.join('\n')}}.channel-info-content .tw-accent-region,.channel-info-content .gocjHQ{${accent_bits.join('\n')}}`);
+ this.css_tweaks.set('colors', `body,body .tw-root--theme-light,body .tw-root--theme-dark {${bits.join('\n')}}.channel-info-content .tw-accent-region,.channel-info-content .gocjHQ{${accent_bits.join('\n')}}`);
else
this.css_tweaks.delete('colors');
}
diff --git a/src/utilities/data/user-bulk.gql b/src/utilities/data/user-bulk.gql
new file mode 100644
index 00000000..ac8291b4
--- /dev/null
+++ b/src/utilities/data/user-bulk.gql
@@ -0,0 +1,8 @@
+query FFZ_UserBulk($ids: [ID!], $logins: [String!]) {
+ users(ids: $ids, logins: $logins) {
+ id
+ login
+ displayName
+ profileImageURL(width: 50)
+ }
+}
\ No newline at end of file
diff --git a/src/utilities/filtering.js b/src/utilities/filtering.js
index d589f77c..22bb8f5a 100644
--- a/src/utilities/filtering.js
+++ b/src/utilities/filtering.js
@@ -26,8 +26,15 @@ export function createTester(rules, filter_types, inverted = false, or = false,
continue;
}
+ // Construct the test. If no test is returned, we skip this filter.
+ // This can happen depending on configuration rendering a method
+ // pointless.
+ const test = type.createTest(rule.data, filter_types, rebuild);
+ if ( ! test )
+ continue;
+
i++;
- tests.push(type.createTest(rule.data, filter_types, rebuild));
+ tests.push(test);
names.push(`f${i}`);
}
diff --git a/src/utilities/twitch-data.js b/src/utilities/twitch-data.js
index 98fab47a..1bdc1169 100644
--- a/src/utilities/twitch-data.js
+++ b/src/utilities/twitch-data.js
@@ -23,6 +23,9 @@ export default class TwitchData extends Module {
this.inject('site.apollo');
+ this._waiting_user_ids = new Map;
+ this._waiting_user_logins = new Map;
+
this._waiting_stream_ids = new Map;
this._waiting_stream_logins = new Map;
@@ -268,6 +271,130 @@ export default class TwitchData extends Module {
}
+ /**
+ * Fetch basic information on a user from Twitch. This is automatically batched
+ * for performance, but not directly cached. Either an id or login must be provided.
+ *
+ * @param {Number|String} [id] The ID of the channel
+ * @param {String} [login] The username of the channel
+ *
+ * @returns {Promise} A basic user object.
+ */
+ getUserBasic(id, login) {
+ return new Promise((s, f) => {
+ if ( id ) {
+ if ( this._waiting_user_ids.has(id) )
+ this._waiting_user_ids.get(id).push([s,f]);
+ else
+ this._waiting_user_ids.set(id, [[s,f]]);
+ } else if ( login ) {
+ if ( this._waiting_user_logins.has(login) )
+ this._waiting_user_logins.get(login).push([s,f]);
+ else
+ this._waiting_user_logins.set(login, [[s,f]]);
+ } else
+ f('id and login cannot both be null');
+
+ if ( ! this._loading_users )
+ this._loadUsers();
+ })
+ }
+
+ async _loadUsers() {
+ if ( this._loading_users )
+ return;
+
+ this._loading_users = true;
+
+ // Get the first 50... things.
+ const ids = [...this._waiting_user_ids.keys()].slice(0, 50),
+ remaining = 50 - ids.length,
+ logins = remaining > 0 ? [...this._waiting_user_logins.keys()].slice(0, remaining) : [];
+
+ let nodes;
+
+ try {
+ const data = await this.queryApollo({
+ query: await import(/* webpackChunkName: 'queries' */ './data/user-bulk.gql'),
+ variables: {
+ ids: ids.length ? ids : null,
+ logins: logins.length ? logins : null
+ }
+ });
+
+ nodes = get('data.users', data);
+
+ } catch(err) {
+ for(const id of ids) {
+ const promises = this._waiting_user_ids.get(id);
+ this._waiting_user_ids.delete(id);
+
+ for(const pair of promises)
+ pair[1](err);
+ }
+
+ for(const login of logins) {
+ const promises = this._waiting_user_logins.get(login);
+ this._waiting_user_logins.delete(login);
+
+ for(const pair of promises)
+ pair[1](err);
+ }
+
+ return;
+ }
+
+ const id_set = new Set(ids),
+ login_set = new Set(logins);
+
+ if ( Array.isArray(nodes) )
+ for(const node of nodes) {
+ if ( ! node || ! node.id )
+ continue;
+
+ id_set.delete(node.id);
+ login_set.delete(node.login);
+
+ let promises = this._waiting_user_ids.get(node.id);
+ if ( promises ) {
+ this._waiting_user_ids.delete(node.id);
+ for(const pair of promises)
+ pair[0](node);
+ }
+
+ promises = this._waiting_user_logins.get(node.login);
+ if ( promises ) {
+ this._waiting_user_logins.delete(node.login);
+ for(const pair of promises)
+ pair[0](node);
+ }
+ }
+
+ for(const id of id_set) {
+ const promises = this._waiting_user_ids.get(id);
+ if ( promises ) {
+ this._waiting_user_ids.delete(id);
+ for(const pair of promises)
+ pair[0](null);
+ }
+ }
+
+ for(const login of login_set) {
+ const promises = this._waiting_user_logins.get(login);
+ if ( promises ) {
+ this._waiting_user_logins.delete(login);
+ for(const pair of promises)
+ pair[0](null);
+ }
+ }
+
+ this._loading_users = false;
+
+ if ( this._waiting_user_ids.size || this._waiting_user_logins.size )
+ this._loadUsers();
+ }
+
+
// ========================================================================
// Broadcast ID
// ========================================================================
diff --git a/styles/native/card.scss b/styles/native/card.scss
index 64e54e94..9bb9aeda 100644
--- a/styles/native/card.scss
+++ b/styles/native/card.scss
@@ -3,6 +3,8 @@
flex-shrink: 0;
width: 100%;
+ &--size-1 { width: 1rem }
+ &--size-105 { width: 1.5rem }
&--size-2 { width: 2rem }
&--size-3 { width: 3rem }
&--size-4 { width: 4rem }