2022-12-28 20:59:08 +00:00
|
|
|
"
|
|
|
|
I model the API for the [Invidious](https://invidious.io/) open source front-end for YouTube.
|
|
|
|
"
|
|
|
|
Class {
|
|
|
|
#name : #Invidious,
|
|
|
|
#superclass : #Object,
|
|
|
|
#instVars : [
|
|
|
|
'uri',
|
|
|
|
'region',
|
2022-12-29 15:13:54 +00:00
|
|
|
'api',
|
|
|
|
'monitor'
|
2022-12-28 20:59:08 +00:00
|
|
|
],
|
2022-12-29 21:58:56 +00:00
|
|
|
#classInstVars : [
|
|
|
|
'default'
|
|
|
|
],
|
2022-12-28 20:59:08 +00:00
|
|
|
#category : #VideoWeb
|
|
|
|
}
|
|
|
|
|
2022-12-29 21:58:56 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> default: anObject [
|
|
|
|
default := anObject
|
|
|
|
]
|
|
|
|
|
2022-12-29 15:13:54 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> defaultInstance [
|
2022-12-29 21:58:56 +00:00
|
|
|
^ default ifNil: [ default := self responseTimes first key ]
|
2022-12-29 15:13:54 +00:00
|
|
|
]
|
|
|
|
|
2022-12-28 20:59:08 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> instances [
|
|
|
|
|
|
|
|
^ self rawInstances collect: [ :instanceData |
|
|
|
|
| instanceDict |
|
|
|
|
instanceDict := instanceData second.
|
|
|
|
Invidious new fromDictionary: instanceDict ]
|
|
|
|
]
|
|
|
|
|
2022-12-29 21:58:56 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> instancesWithAPIEnabled [
|
|
|
|
^ self instances select: [ :instance | instance api = true ]
|
|
|
|
]
|
|
|
|
|
2022-12-28 20:59:08 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> rawInstances [
|
|
|
|
^ STON
|
|
|
|
fromString: 'https://api.invidious.io/instances.json?sort_by=type,users' asUrl
|
|
|
|
retrieveContents
|
|
|
|
]
|
|
|
|
|
2022-12-29 21:58:56 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> responseTimes [
|
|
|
|
| responses |
|
|
|
|
responses := Dictionary new.
|
2022-12-30 00:33:29 +00:00
|
|
|
self instancesWithAPIEnabled do: [ :instance |
|
|
|
|
responses at: instance put: instance responseTime.
|
2022-12-29 21:58:56 +00:00
|
|
|
].
|
|
|
|
^ (responses associations asSortedCollection: [ :x :y| x value < y value ])
|
|
|
|
collect: [:assoc | assoc ]
|
|
|
|
]
|
|
|
|
|
2023-01-07 00:59:04 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious class >> storeConfiguration [
|
|
|
|
|
|
|
|
| configFolder |
|
|
|
|
configFolder := (FileLocator userData / 'Mutabit' / 'VideoWeb') ensureCreateDirectory.
|
|
|
|
MarkupFile exportAsFileOn: configFolder / 'config.ston' containing: ( STON toStringPretty: self defaultInstance ).
|
|
|
|
^ configFolder / 'config.ston'
|
|
|
|
]
|
|
|
|
|
2022-12-29 15:43:43 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> api [
|
|
|
|
^ api
|
|
|
|
]
|
|
|
|
|
2022-12-28 20:59:08 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> api: booleanValue [
|
2022-12-29 15:43:43 +00:00
|
|
|
api := booleanValue.
|
2022-12-28 20:59:08 +00:00
|
|
|
]
|
|
|
|
|
2023-01-07 00:59:04 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> authorIdForVideo: aString [
|
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> channel: authorId [
|
2023-01-09 15:44:35 +00:00
|
|
|
| queryURL dataDict |
|
2023-01-07 00:59:04 +00:00
|
|
|
queryURL := self uri asString, 'api/v1/channels/', authorId .
|
2023-01-09 15:44:35 +00:00
|
|
|
dataDict := STONJSON fromString: queryURL asUrl retrieveContents.
|
|
|
|
^ VideoChannel new fromDictionary: dataDict
|
2023-01-07 00:59:04 +00:00
|
|
|
]
|
|
|
|
|
2023-01-07 19:08:51 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> channelContainingVideo: videoID [
|
|
|
|
^ self channel: (self video: videoID) authorId
|
|
|
|
]
|
|
|
|
|
2022-12-28 20:59:08 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> fromDictionary: aDictionary [
|
2022-12-29 15:13:54 +00:00
|
|
|
| rawMonitor|
|
2022-12-28 20:59:08 +00:00
|
|
|
self
|
|
|
|
uri: (aDictionary at: 'uri');
|
|
|
|
region: (aDictionary at: 'region');
|
2022-12-29 15:13:54 +00:00
|
|
|
api: (aDictionary at: 'api').
|
|
|
|
rawMonitor := aDictionary at: 'monitor'.
|
|
|
|
rawMonitor ifNil: [ ^ self ].
|
|
|
|
self monitor
|
|
|
|
at: '90DaysRatio' put: ((aDictionary at: 'monitor' at: '90dRatio') at: 'ratio');
|
|
|
|
at: '30DaysRatio' put: ((aDictionary at: 'monitor' at: '30dRatio') at: 'ratio');
|
|
|
|
yourself.
|
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> monitor [
|
|
|
|
^ monitor ifNil: [ monitor := Dictionary new]
|
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> monitor: aDictionary [
|
|
|
|
monitor := aDictionary
|
2022-12-28 20:59:08 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> printOn: aStream [
|
2022-12-29 15:43:43 +00:00
|
|
|
| ratio |
|
|
|
|
ratio := self monitor at: '90DaysRatio' ifAbsent: [ '--' ].
|
2022-12-28 20:59:08 +00:00
|
|
|
super printOn: aStream.
|
2022-12-29 15:43:43 +00:00
|
|
|
^ aStream nextPutAll: ' ( ', self uri asString, ' | ', self region, ' | ', ratio, '% ) '
|
2022-12-28 20:59:08 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> region [
|
|
|
|
^ region
|
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> region: countryISOCode [
|
|
|
|
region := countryISOCode
|
|
|
|
]
|
|
|
|
|
2022-12-30 00:33:29 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> responseTime [
|
|
|
|
^ [ ZnClient new
|
|
|
|
beOneShot;
|
|
|
|
url: self uri;
|
|
|
|
get;
|
|
|
|
response ] timeToRun
|
|
|
|
]
|
|
|
|
|
2022-12-28 20:59:08 +00:00
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> uri [
|
|
|
|
^ uri
|
|
|
|
]
|
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> uri: urlString [
|
|
|
|
uri := urlString asUrl
|
|
|
|
]
|
2023-01-07 18:01:14 +00:00
|
|
|
|
|
|
|
{ #category : #accessing }
|
|
|
|
Invidious >> video: videoId [
|
|
|
|
| dataUrl queryFields dataDict |
|
|
|
|
queryFields := 'videoId,title,description,author,authorId,authorUrl,likeCount,lengthSeconds,videoThumbnails'.
|
|
|
|
dataUrl := (self uri asString, 'api/v1/videos/', videoId, '?fields=', queryFields, '&pretty=1') asUrl.
|
|
|
|
dataDict := STONJSON fromString: dataUrl retrieveContents.
|
|
|
|
^ WebVideo new fromDictionary: dataDict
|
|
|
|
]
|