Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Switch to helix API #852

Merged
merged 45 commits into from
Jan 24, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
0041432
build: add webpack YAML config for test fixtures
bastimeyer Jan 11, 2022
77431e0
tests: add more utility functions to store-utils
bastimeyer Jan 11, 2022
09c28f4
data: update TwitchAdapter + TwitchSerializer
bastimeyer Jan 11, 2022
c2d252d
data: remove old models, adapters and serializers
bastimeyer Jan 11, 2022
df6c140
data: rewrite TwitchGame
bastimeyer Jan 11, 2022
23d082e
data: rewrite TwitchGameTop
bastimeyer Jan 11, 2022
b1e1346
data: rewrite TwitchChannel
bastimeyer Jan 11, 2022
b08136b
data: rewrite TwitchUser
bastimeyer Jan 11, 2022
59ee57b
data: add TwitchUserFollowed
bastimeyer Jan 12, 2022
e358114
data: rewrite TwitchTeam
bastimeyer Jan 11, 2022
35e7a6f
data: rewrite TwitchStream
bastimeyer Jan 12, 2022
c957d56
data: rewrite TwitchStreamFollowed
bastimeyer Jan 11, 2022
85e3fc2
data: rewrite TwitchSearchGame
bastimeyer Jan 12, 2022
401c6e6
data: rewrite TwitchSearchChannel
bastimeyer Jan 12, 2022
3d942a3
data: implement TwitchImageTransform
bastimeyer Jan 12, 2022
3a747c2
ui/components: update button components
bastimeyer Jan 17, 2022
45e0d06
ui/components: update StatsRowComponent
bastimeyer Jan 17, 2022
6766a24
services/auth: helix API
bastimeyer Jan 14, 2022
70a29de
services/notification: helix API
bastimeyer Jan 15, 2022
fd159d8
services/chat: helix API
bastimeyer Jan 17, 2022
528865e
services/streaming: helix API
bastimeyer Jan 17, 2022
d197cea
ui/routes: remove FeaturedRoute
bastimeyer Jan 14, 2022
3c00960
ui/routes: refactor InfiniteScrollMixin
bastimeyer Jan 23, 2022
d22b373
ui/routes: add InfiniteScrollPaginationMixin
bastimeyer Jan 18, 2022
c43b00e
ui/routes: fix Games{Index,Game}Route
bastimeyer Jan 18, 2022
4cfb078
ui/routes: fix StreamsRoute
bastimeyer Jan 18, 2022
a76ebd2
ui/routes: fix UserFollowedStreamsRoute
bastimeyer Jan 18, 2022
d727967
ui/routes: fix UserFollowedChannelsRoute
bastimeyer Jan 18, 2022
605d96e
ui/routes: fix Channel{,Index,Teams,Settings}Route
bastimeyer Jan 20, 2022
0a61ea1
ui/routes: fix Team{,Index,Members,Info}Route
bastimeyer Jan 20, 2022
3fd51e2
ui/routes: fix WatchingRoute
bastimeyer Jan 21, 2022
13b3242
ui/routes: fix SettingsChannelsRoute
bastimeyer Jan 21, 2022
a21cf04
ui/components: fix GameItemComponent
bastimeyer Jan 20, 2022
6e1fdb5
ui/components: fix ChannelItemComponent
bastimeyer Jan 20, 2022
8857924
ui/components: fix TeamItemComponent
bastimeyer Jan 20, 2022
8074479
ui/components: fix StreamItemComponent
bastimeyer Jan 20, 2022
a72804c
ui/components: fix PreviewImageComponent
bastimeyer Jan 20, 2022
10b0bc3
ui/components: fix StreamPreviewImageComponent
bastimeyer Jan 20, 2022
3d4de9c
ui/components: fix StreamPresentationComponent
bastimeyer Jan 21, 2022
b00a70d
ui/components: fix SettingsChannelItemComponent
bastimeyer Jan 21, 2022
f3390d9
ui/components: drop QuickBarRandomStreamComponent
bastimeyer Jan 21, 2022
0ecfc67
data: update Search model, fix localStorage
bastimeyer Jan 21, 2022
715bd0e
ui/components: update SearchBarComponent
bastimeyer Jan 21, 2022
e45a695
ui/routes: fix SearchRoute
bastimeyer Jan 21, 2022
f55aafa
data: fix box_art_url bug in TwitchSearchGame
bastimeyer Jan 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions build/tasks/webpack/configurators/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ module.exports = {
});
},

common( config ) {
config.module.rules.push({
test: /\.ya?ml$/,
include: pTestFixtures,
type: "json",
use: [
"yaml-loader"
]
});
},

test( config ) {
this._tests( config );
this._aliases( config );
Expand Down
22 changes: 12 additions & 10 deletions src/app/data/models/auth/model.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,28 @@
import { get, computed } from "@ember/object";
import { computed } from "@ember/object";
import attr from "ember-data/attr";
import Model from "ember-data/model";


// noinspection JSValidateTypes
export default Model.extend( /** @class Auth */ {
/** @type {string} */
access_token: attr( "string" ),
scope : attr( "string" ),
date : attr( "date" ),
/** @type {string} */
scope: attr( "string" ),
/** @type {Date} */
date: attr( "date" ),


// volatile property
// state properties
user_id: null,
user_name: null,

// status properties
isPending : false,
isPending: false,
isLoggedIn: computed( "access_token", "user_id", "isPending", function() {
let token = get( this, "access_token" );
let id = get( this, "user_id" );
let pending = get( this, "isPending" );
/** @this {Auth} */
const { access_token, user_id, isPending } = this;

return token && id && !pending;
return access_token && user_id && !isPending;
})

}).reopenClass({
Expand Down
42 changes: 11 additions & 31 deletions src/app/data/models/search/model.js
Original file line number Diff line number Diff line change
@@ -1,42 +1,22 @@
import { get, computed } from "@ember/object";
import attr from "ember-data/attr";
import Model from "ember-data/model";


const { hasOwnProperty } = {};


export default Model.extend({
query : attr( "string" ),
// noinspection JSValidateTypes
export default Model.extend( /** @class Search */ {
/** @type {string} */
query: attr( "string" ),
/** @type {string} */
filter: attr( "string" ),
date : attr( "date" ),

label: computed( "filter", function() {
const filter = get( this, "filter" );
return this.constructor.getLabel( filter );
})
/** @type {Date} */
date: attr( "date" )

}).reopenClass({
toString() { return "Search"; },

filters: [
{ label: "All", id: "all" },
{ label: "Game", id: "games" },
{ label: "Channel", id: "channels" },
{ label: "Stream", id: "streams" }
],

filtersmap: computed(function() {
return this.filters.reduce( ( map, filter ) => {
map[ filter.id ] = filter;
return map;
}, {} );
}),

getLabel( filter ) {
const map = get( this, "filtersmap" );
return hasOwnProperty.call( map, filter )
? map[ filter ].label
: "All";
}
{ id: "all" },
{ id: "games" },
{ id: "channels" }
]
});
2 changes: 1 addition & 1 deletion src/app/data/models/settings/gui/fragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export default Fragment.extend({
externalcommands: attr( "boolean", { defaultValue: false } ),
focusrefresh: attr( "number", { defaultValue: ATTR_GUI_FOCUSREFRESH_NONE } ),
hidebuttons: attr( "boolean", { defaultValue: false } ),
homepage: attr( "string", { defaultValue: "/featured" } ),
homepage: attr( "string", { defaultValue: "/streams" } ),
integration: attr( "number", { defaultValue: ATTR_GUI_INTEGRATION_BOTH } ),
language: attr( "string", { defaultValue: "auto" } ),
minimize: attr( "number", { defaultValue: ATTR_GUI_MINIMIZE_NOOP } ),
Expand Down
40 changes: 19 additions & 21 deletions src/app/data/models/stream/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,14 +64,18 @@ export {
};


/**
* @class Stream
*/
export default Model.extend({
/** @property {TwitchStream} stream */
stream: belongsTo( "twitchStream", { async: false } ),
/** @property {TwitchChannel} channel */
channel: belongsTo( "twitchChannel", { async: false } ),
export default Model.extend( /** @class Stream */ {
/** @type {AuthService} */
auth: service(),
/** @type {SettingsService} */
settings: service(),
/** @type {StreamingService} */
streaming: service(),

/** @type {TwitchStream} */
stream: belongsTo( "twitch-stream", { async: false } ),
/** @type {TwitchUser} */
user: belongsTo( "twitch-user", { async: false } ),
quality: attr( "string" ),
low_latency: attr( "boolean" ),
disable_ads: attr( "boolean" ),
Expand All @@ -96,12 +100,6 @@ export default Model.extend({
log: null,
showLog: false,


auth: service(),
settings: service(),
streaming: service(),


session: alias( "auth.session" ),


Expand Down Expand Up @@ -166,14 +164,14 @@ export default Model.extend({
cpQualityFromPresetOrCustomValue( "quality" )
),

streamUrl: computed( "channel.name", function() {
const channel = get( this, "channel.name" );

return twitchStreamUrl.replace( "{channel}", channel );
})
streamUrl: computed(
"stream.user_login",
/** @this {Stream} */
function() {
return twitchStreamUrl.replace( "{channel}", this.stream.user_login );
}
)

}).reopenClass({

toString() { return "Stream"; }

});
122 changes: 68 additions & 54 deletions src/app/data/models/twitch/adapter.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { get, observer } from "@ember/object";
import { inject as service } from "@ember/service";
import RESTAdapter from "ember-data/adapters/rest";
import { twitch } from "config";
import AdapterMixin from "data/models/-mixins/adapter";
Expand All @@ -9,42 +8,18 @@ const { oauth: { "client-id": clientId } } = twitch;


export default RESTAdapter.extend( AdapterMixin, {
auth: service(),

host: "https://api.twitch.tv",
namespace: "",
headers: {
"Accept": "application/vnd.twitchtv.v5+json",
"Client-ID": clientId
},

defaultSerializer: "twitch",


urlFragments: {
user_id() {
let user_id = get( this, "auth.session.user_id" );
if ( !user_id ) {
throw new Error( "Unknown user_id" );
}

return user_id;
},
user_name() {
let user_name = get( this, "auth.session.user_name" );
if ( !user_name ) {
throw new Error( "Unknown user_name" );
}

return user_name;
}
},


coalesceFindRequests: false,

findManyIdString: null,
findManyIdSeparator: ",",
findIdParam: null,
findIdSeparator: null,
findIdMax: 100,


access_token: null,
Expand All @@ -53,7 +28,7 @@ export default RESTAdapter.extend( AdapterMixin, {
if ( token === null ) {
delete this.headers[ "Authorization" ];
} else {
this.headers[ "Authorization" ] = `OAuth ${token}`;
this.headers[ "Authorization" ] = `Bearer ${token}`;
}
}),

Expand All @@ -69,61 +44,100 @@ export default RESTAdapter.extend( AdapterMixin, {
return {};
},

findMany( store, type, ids, snapshots ) {
const url = this.buildURL( type, null, snapshots, "findMany" );
/**
* @param {DS.Store} store
* @param {DS.Model} type
* @param {string} id
* @param {DS.Snapshot} snapshot
* @return {Promise}
*/
findRecord( store, type, id, snapshot ) {
const url = this.buildURL( type, null, snapshot, "findRecord" );
const paramName = this.findIdParam || store.serializerFor( type.modelName ).primaryKey;
const data = {
[ this.findManyIdString ]: ids.join( this.findManyIdSeparator )
[ paramName ]: id
};

return this.ajax( url, "GET", { data } );
},

/**
* @param {DS.Store} store
* @param {DS.Model} type
* @param {string[]} ids
* @param {DS.Snapshot[]} snapshots
* @return {Promise}
*/
findMany( store, type, ids, snapshots ) {
const url = this.buildURL( type, null, snapshots, "findMany" );
const paramName = this.findIdParam || store.serializerFor( type.modelName ).primaryKey;
const data = this.findIdSeparator
? { [ paramName ]: ids.join( this.findIdSeparator ) }
: ids.map( id => ({ name: paramName, value: id }) );

return this.ajax( url, "GET", { data } );
},


/**
* @param {DS.Store} store
* @param {DS.Snapshot[]} snapshots
* @return {Array<Array<DS.Snapshot>>}
*/
groupRecordsForFindMany( store, snapshots ) {
const snapshotsByType = new Map();

// group snapshots by type
snapshots.forEach( snapshot => {
const type = snapshot.type;
const typeArray = snapshotsByType.get( type ) || [];
typeArray.push( snapshot );
snapshotsByType.set( type, typeArray );
});
for ( const snapshot of snapshots ) {
const { type } = snapshot;
let snapshotGroup = snapshotsByType.get( type );
if ( !snapshotGroup ) {
snapshotGroup = [];
snapshotsByType.set( type, snapshotGroup );
}
snapshotGroup.push( snapshot );
}

// build request groups
const groups = [];
snapshotsByType.forEach( ( snapshotGroup, type ) => {
for ( const [ type, snapshotGroup ] of snapshotsByType ) {
const adapter = store.adapterFor( type.modelName );

const baseLength = adapter._buildURL( type ).length
// "?[findManyIdString]="
+ 2 + adapter.findManyIdString.length;
const findManyIdSeparatorLength = adapter.findManyIdSeparator.length;
const maxLength = adapter.maxURLLength;
const {
maxURLLength,
findIdParam,
findIdMax,
findIdSeparator
} = adapter;

const baseLength = adapter._buildURL( type ).length;
const paramName = findIdParam || store.serializerFor( type.modelName ).primaryKey;
const paramNameLength = paramName.length;
const findIdSeparatorLength = findIdSeparator?.length || 0;

let group = [];
let length = baseLength;

snapshotGroup.forEach( snapshot => {
const id = get( snapshot, "record.id" );
const idLength = String( id ).length;
const separatorLength = group.length === 0 ? 0 : findManyIdSeparatorLength;
const newLength = length + separatorLength + idLength;
for ( const snapshot of snapshotGroup ) {
length += group.length === 0 || findIdSeparatorLength === 0
// ${url}?${paramName}=${id1} ... &${paramName}=${id2}
? 2 + paramNameLength
// ${url}?${paramName}=${id1} ... ${findIdSeparator}${id2}
: findIdSeparatorLength;
length += String( snapshot.record.id ).length;

if ( newLength <= maxLength ) {
if ( length <= maxURLLength && group.length < findIdMax ) {
group.push( snapshot );
length = newLength;
} else {
groups.push( group );
group = [ snapshot ];
length = baseLength;
}
});
}

if ( group.length ) {
groups.push( group );
}
});
}

return groups;
}
Expand Down
13 changes: 0 additions & 13 deletions src/app/data/models/twitch/channel-followed/model.js

This file was deleted.

Loading