Behaviors
Quick Start
Requirements: Node.js
To use this project you must first install its dependencies
$ yarn install
# or "npm install"
Once you have installed the dependencies you are ready to start using the project
Via Docker
To build the behaviors docker image (webrecorder/behaviors:latest
) execute docker-compose build
.
The image created is suitable for building behaviors and running the behavior api server.
The default configuration of the image is to run the api server, however you can substitute the default command with any of the cli commands listed previously.
For more information please consult the provided Dockerfile
and docker-compose.yml
files.
Behaviors
Format
A behavior is simply a JavaScript file that exposes the means to perform its series of actions in a page and some information (metadata) about itself.
With this in mind, every behavior is expected to be JavaScript module that
- has a default export that is an async generator function or a function returning an async iterator
- has named export metadata that is an object
- has named export isBehavior
An example of the expected format behavior is shown below
// means to perform the series of actions
export default async function* myBehavior(cliAPI) { ... }
// information about the behavior
export const metadata = { ... };
// flag indicating this file is a behavior ready to be used
export const isBehavior = true;
// optional function to be called after each step of the behavior
export function postStep(rawBehaviorStepResults) { ... }
In the example above, the behavior exposes the means to perform its actions using the export default
keywords.
The export default
keywords indicate that whatever follows is the primary export of the module and what ever is default export of a behavior is used to run the behavior.
Any additional information that the behavior wishes to be expose using the export
keyword and is shown in the example above with the final two required named exports metadata and isBehavior.
Please note that isBehavior named export is used to indicate that this behavior is ready to be used.
If the isBehavior export is missing then the provided tools will not recognize the behavior as being ready and will not use the behavior.
Likewise, if the behavior does not have a default export and does not export metadata and isBehavior, the tools will not consider the behavior as valid.
The optional export postStep
is a function called after each action (step) of the behavior to convert the yielded results into the expected format.
It is recommended that you use the library function lib.buildCustomPostStepFn if you want to perform some kind of action after each behavior step that is not directly tied to the running of the behavior.
export const postStep = lib.buildCustomPostStepFn(() => { ... });
Metadata
A behaviors exported metadata is used to
- describe how it should be matched to the pages it is written for
- provide an overview of what it does
- have a more specific name associated with it when querying for it using the behavior api
- embed any additional information about the behavior
And every exported metadata object is expected to have the following properties
- name (string): the name for your behavior to be used when querying the behavior API for it by name
- description (string): a description for the behavior
- match (object): how the behavior will be matched to the page(s) it is written for
Of the expected metadata properties, the match object has two variations and is shown below in the context of two valid metadata exports.
// variation 1
export const metadata = {
name: 'the name of your behavior',
match: {
regex: /an regular expression dictating the URL the behavior will run on/,
},
description: 'an description of what your behavior does',
};
The first variation, shown above, defines a single property regex
that is an JavaScript RegExp.
The behavior using variation one is considered matched to an URL when the regular expression, defined in the regex
property of match
, matches the URL.
The second variation, shown below, has two properties base
(RegExp) and sub
(Array<RegExp>).
The base
regular expression is used as a generic test and if it matches a URL the regular expressions in the sub
array will be tested against the same URL.
The behavior is considered matched to a URL when the base
regular expression matches the URL and one of the sub
regular expressions also matches the URL.
// variation 2
export const metadata = {
name: 'the name of your behavior',
match: {
regex: {
base: /an regular expressions dictating the base URL the behavior will run on/,
sub: [
/an array of regular expressions dictating more specific parts of the base URL the behavior will run on/,
],
},
},
description: 'an description of what your behavior does',
};
Behavior Implementation Overview
The primary reasons that a behaviors default export is required to be an async generator function or a function returning an async iterator are
- Async generators are a native JavaScript feature cross the major browser
- They provide a simple way to run the behavior via in the browser and via browsertrix
- Allow information about the behavior, its state, to be easily reported to behavior runners
However we understand this requirement, namely behaviors as async generators, may be a new JavaScript idiom for some and for the remaining portion of this section give a high level overview on how to write a behavior under this requirement.
Now consider the following example shown below which is a behavior living in the in the "behaviors" directory of this project for all pages of myAwesomeWebSite.com.
Please note that there is no code in the body of the myBehavior
function, this is ok as all the remaining code examples should be assumed to be inside function where the comment "behavior code" is currently.
Also note that their exists a cli command for new behavior creation that will fill out much of the boiler plate shown in the code section below
import * as lib from '../lib';
export default async function* myBehavior(cliAPI) {
// behavior code
}
export const metadata = {
name: 'myBehavior',
match: {
regex: /^(?:https?:\/\/(?:www\.)?)?:myAwesomeWebSite.com.*$/,
},
description: 'It does really cool stuff',
};
export const isBehavior = true;
As you will have already noticed by looking over the documentation for the behaviors standard library that many of the functions returns Promises.
Now without turning into a JavaScript tutorial the only thing you need to know about promises is that they can be awaited, that is to say you can await for their completion.
This comes in handy when you want to wait for the the documents state to become ready since the pages of myAwesomeWebSite.com take a long time to load and can be done as easily as shown in step 1
// step 1
await lib.domCompletePromise();
Now we know that the browser has fully parsed the page and we can safely start operating on the page.
But first we should let ourselves know that we are good to go by reporting some state and is done by yielding a value as shown in step 2
// step 1
await lib.domCompletePromise();
// step 2
const state = { videosPlayed: 0 };
yield lib.stateWithMsgNoWait('Document ready!', state);
The function lib.stateWithMsgNoWait
indicates to the behavior runner that the behavior has an updated to report and that it does not have to wait.
If the behavior was being run by browsertrix and the other function lib.stateWithMsgWait
was used, browsertrix would have waited until the HTTP requests made by the page had died down (no request made for set period of time) but since we use the no wait variant we know no wait will be made.
When you yield
a value from the behavior you can consider the behavior paused until the runner initiates an the next action.
If a wait was indicated using the lib.stateWithMsgWait
and the behavior is being run by browsertrix no more actions would be initiated until the pages network (amount of HTTP requests made) become idle (no more requests made for a set period of time).
Additionally, it should be noted that the second argument supplied to lib.stateWithMsgNoWait
is optional but useful for reporting to yourself more detailed information about the state of your behavior.
Continuing on with the creation of our behavior, let us assume that the page that the behavior is operating in has a list videos we want to play.
We can accomplish this as shown in step 3
// step 1
await lib.domCompletePromise();
// step 2
const state = { videosPlayed: 0 };
yield lib.stateWithMsgNoWait('Document ready!', state);
// step 3
for (const videoListItem of lib.childElementIterator(lib.id('videos'))) {
// videoListItem is a child of the element with id == 'videos'
// that has a video as child element
const videoWasPlayed = await lib.selectAndPlay('video', videoListItem);
if (videoWasPlayed) {
// increment our states counter for number of videos played
state.videosPlayed += 1;
// let ourselves know we played a video
yield lib.stateWithMsgNoWait('Played a video!', state);
} else {
yield lib.stateWithMsgNoWait('Failed to play a video using the standard DOM methods', state);
}
}
return lib.stateWithMsgNoWait('Done!', state);
In step three we use the function childElementIterator
that returns an iterator over the child elements of the supplied parent element and then for each child of the element with `id="videos" we
- select the video element that is a descendant of the
videoListItem
s and play the video - increment the number of videos played in our behaviors state
- let ourselves know that we played a video
Also seen in step 3 is the usage keyword yield
in combination with *
or yield *
.
yield *
means that we are yielding another generator, that is to say all actions of the generator are to be treated as if we yielded them ourselves.
In short step 3 can be described as playing a video contained in every child of the element with id == video and once we have played all the videos on the page return a message with our final state from the behavior.
This completes the mini-tutorial on how to create behaviors.
The full behavior is shown below
import * as lib from '../lib';
export default async function* myBehavior(cliAPI) {
// behavior code
// step 1
await lib.domCompletePromise();
// step 2
const state = { videosPlayed: 0 };
yield lib.stateWithMsgNoWait('Document ready!', state);
// step 3
for (const videoListItem of lib.childElementIterator(lib.id('videos'))) {
// videoListItem is a child of the element with id == 'videos'
// that has a video as child element
const videoWasPlayed = await lib.selectAndPlay('video', videoListItem);
if (videoWasPlayed) {
// increment our states counter for number of videos played
state.videosPlayed += 1;
// let ourselves know we played a video
yield lib.stateWithMsgNoWait('Played a video!', state);
} else {
yield lib.stateWithMsgNoWait('Failed to play a video using the standard DOM methods', state);
}
}
return lib.stateWithMsgNoWait('Done!', state);
}
export const metadata = {
name: 'myBehavior',
match: {
regex: /^(?:https?:\/\/(?:www\.)?)?:myAwesomeWebSite.com.*$/,
},
description: 'It does really cool stuff',
};
export const isBehavior = true;
Development Workflow
Automated
The simplest way to both develop and run a behavior on the target page is to use the provided behavior runner cli and a run configuration file (more details).
To help you get started a behavior run configuration file, behavior-run-config.yml
found at the root of this project, has been provided for you.
By using the provided configuration file all that is required is to change two fields:
- behavior: the path to your new behavior in the behavior directory of this project
- url: the url of the page your behavior should be run in
Once you have changed those two you fields you can start the build and run process by either executing one of the following from the root directory of this project
./bin/cli runner -c behavior-run-config.yml
./bin/cli-runner -c behavior-run-config.yml
The command will launch a Chrome/Chromium browser installed on your computer, build the behavior, and then run it until completion.
While the behavior is being run or the behavior has run to completion and a change has been detected to the behavior or any of the files it includes, it will be rebuilt and re-run automatically.
Manual
To build the behavior execute the following command ./bin/cli-behaviors -b ./behaviors/<path to your behavior>
.
Once the command exits the behavior ready to be run can be found at ./dist/<behavior name>.js
or you can copy the path displayed
in the output of the build command.
The next step is to copy the contents of the generated file into the browser and run it.
The generated file contains JavaScript that will setup the behavior for running using an utility class exposed on window
as $WBBehaviorRunner$
.
Shown below are the ways provided for you to manually run the behavior by the utility class.
/* automatic running, chose 1 method */
(async () => {
for await (const state of $WBBehaviorRunner$.autoRunIter()) {
console.log(state);
}
/* or */
await $WBBehaviorRunner$.autoRun({logging: true});
/* or */
await $WBBehaviorRunner$.autoRunWithDelay({logging: true});
})();
/* manually initiate each step of the behavior */
(async () => {
while (true) {
const state = await $WBBehaviorRunner$.step();
console.log(state);
if (state.done) break;
}
})();
The autoRunIter
function accepts a single optional argument delayAmount (number), which is a time value in milliseconds that will be applied after each action (step) of the behavior.
Both the autoRun
and autoRunWithDelay
methods accept a single optional argument options (object) with one exception, autoRunWithDelay
defaults to applying a one second delay after each action if no delay was specified.
The full configuration options for these two methods are displayed below
- delayAmount (number, defaults to 1000): Time value in milliseconds representing how much time should be waited after initiating a behavior's step
- noOutlinks (boolean, defaults to true): Should the collection of outlinks be disabled when running the behavior
- logging (boolean, defaults to true): Should information the behavior sends be displayed
If you use one of the three way to "automatically" run the behavior and you wish to pause it while it is running set window.$WBBehaviorPaused
to true and to un-pause it set window.$WBBehaviorPaused
to false.
Build System
Overview
The behavior build process has three phases
- Initialization
- Collection
- Building
Initialization
Initialization has three steps
- Ultimate build configuration
- Building what resolution
- Ensuring the necessary build directory structure exists
Ultimate build configuration
The ultimate build configuration is created in combination with user supplied cli options using the following steps
- If a config was specified using
-c, --config
it is used - If the default config exists in the current working directory of the commands it used
- Otherwise the path to the behavior file or dir (
-b, --build [fileOrDir]
) is used and the six config values are set to the project defaults
When a config file is used each of the six values from the config file are resolved as follows
- if the key exists and value is relative, make absolute by resolving it against the directory containing the config file
- if the key exists and is absolute, use key value
- if key does not exist use project default value
- build, dist:
<directory containing config>/<name>
- lib, tsconfig: projects default value
- metadata: placed in current working directory
- build, dist:
Once the ultimate build configuration has been created, the build process proceeds to the next step.
Building what resolution
The determination for what is being built is done using the value for the -b, --build
cli option and that value can be one of two types
boolean
: build all behaviors found in the value for thebehaviors
key from the supplied build configstring
: path to a directory containing behaviors or a single behavior to be built
When the value for build is boolean
- If the directory supplied via the
behaviors
config key exists, the what is being built is that directory and the initialization process contains to the next step - Otherwise the directory supplied via the
behaviors
config key does not exist the build process is ended
When the value for build is a string
and an absolute path
- If the path exists, the what is being built is that directory or file and the initialization process contains to the next step
- Otherwise the path does not exist the build process is ended
When the value for build is a string
and an relative path, it is resolved in the following order
- the value as is resolved using node's relative path resolution algorithm. Note this value is used by other steps if previous ones fail and is denoted as
resolvedPath
- the value as is joined with the supplied configs behavior dir or projects default behavior dir
- the value as is joined with the the current working directory
resolvedPath
joined with the supplied configs behavior dir or projects default behavior dirresolvedPath
joined with the current working directory
If any of the absolute paths described above exist, the what is being built is the resolved path and the initialization process contains to the next step otherwise the build process is ended
Ensuring the necessary build directory structure exists
The final step in the initialization process is to ensure that the build
and dist
directories exist.
These values may differ from the names used previously only when they are supplied by the user in a build config file.
The build
directory is used to hold intermediate files used by the build system in order to setup the behavior for final building and usage by other tools such as our own running system.
Any setup in order to facilitate running the behavior is done here.
The dist
directory is where the built, bundled, behaviors are placed alongside their metadata if configured to do so.
Collection
The collection phase operates in one of two modes
single behavior
: when thewhat is being built
path resolves to filemulti-behavior
: when thewhat is being built
path resolves to a directory
The primary difference between modes is that multi-behavior
mode considers every file contained in the directory and its descendant directories.
Both modes use the same means in determining if a file is indeed a behavior which is as follows
- the file is an es module
- has a
metadata
ormetaData
named export - has a
isBehavior
named export
Once the behavior(s) have been collected a report is printed stating how many behaviors were found and if any of the files considered partially met the requirements for collection.
Note: Both the collection and building phases share modes with the mode operating under set by the collection phase.
Building
The building phase can be described in the following steps:
- Extract behaviors metadata
- Create the behavior's intermediate file in the configured
build
directory - Use build behavior using rollup, built behavior placed in configured
dist
directory - Once all behaviors have been built generate behavior metadata.
The previous steps are applied to all behaviors returned by the collection phase
CLI
A cli is provided to help you use this project.
The commands available to you are displayed below
$ ./bin/cli --help
Usage: cli <command> [options]
Options:
-V, --version output the version number
-h, --help output usage information
Commands:
api [options] Start the behavior api sever
behaviors [options] Build and or validate behaviors, or generate their metadata
newBehavior [options] Create a new behavior
runner [options] <path-to-behavior> Run and or build a behaviors
stdlib [options] Commands specific to working with the behavior's std library
help [cmd] display help for [cmd]
The cli provides four commands api
, behaviors
, runner
, and stdlib
and each command has its own options.
API command
The api command allows you to start a server for serving your built behaviors.
To run the behavior api server execute ./bin/cli api --build-behaviors
.
This will start the api server after all behaviors provided by wr-behaviors have been built.
If you have already built the behaviors using the behaviors
command provided by the cli then you may omit the --build-behaviors
flag.
Once the server is started the following endpoints are available
/behavior?<match how>
: endpoint for retrieving a behavior's code/info?<match how>
: endpoint for retrieving a behavior's metadata/info-list?<match how>
: endpoint for retrieving the metadata for all behavior's that match/info-all
: endpoint for retrieving the metadata for every behavior
match how
name=<name of the behavior>
url=<URL of page a behavior matches>
The full options that available for use with this command are show below.
$ ./bin/cli api --help
Usage: cli-api [options]
Options:
-V, --version output the version number
-p, --port [port] The port the api server is to bind to (default: 3030)
-h, --host [host] The host address the server is listen on (default: "127.0.0.1")
-b, --behaviorDir [behaviorDir] The path to the directory containing the build behaviors (default: "<cwd>/dist")
-m, --behaviorMetadata [medataPath] The path to the behavior metadata (default: "<cwd>/dist/behaviorMetadata.js")
--build-behaviors Should the api server build the behaviors for starting up
-w, --workers [numWorkers] How many behavior lookup workers should be spawned (default: 2)
-h, --help output usage information
Some configuration of the api server can be done via the environment variables listed below
BEHAVIOR_API_HOST
: the host the api server will use (e.g. 127.0.0.1)BEHAVIOR_API_PORT
: the port the api server will listen on (e.g. 3030)WR_BEHAVIOR_DIR
: path to the directory containing the built behaviorsWR_BEHAVIOR_METADATA_PATH
: path to the behavior metadata fileBUILD_BEHAVIORS
: should the api server build the behaviors before startingNUM_WORKERS
: how many lookup workers should be spawned
Build command
To build the behaviors made available by the project execute ./bin/cli behaviors -b
.
This will build the behaviors using the behavior config file located in the root of this project.
The built behaviors, along with a behavior metadata file (behaviorMetadata.js
), can be found in the dist
directory which will be created for you if it does not exist in the root of this project.
The full options that available for use with this command are show below.
$ ./bin/cli build --help
Usage: cli-build [options]
Options:
-V, --version output the version number
-v, --validate [fileOrDir]
-c, --config [configPath] Path to the behavior config file (default: "<cwd>/dist/behavior-config.yml")
-b, --build [fileOrDir] Build a behaviors or all behaviors contained within a directory (default: true)
-w, --watch [behaviorFileOrDir] Watch the files, and their imports, in the build directory for re-bundling on changes (placed in dist directory)
--metadata [dumpDir] Generate behavior metadata, optionally supplying a path to directory where metadata is to be placed. Defaults to current working directory
-h, --help output usage information
The config file has six keys and should specified in the config as key: value
behaviors
: path to the directory containing the un-built behaviorslib
: path to the directory containing the provided behavior library or own librarybuild
: path to the directory where the intermediate files will be placed (for running using Webrecorders system)dist
: path to directory where the fully built behaviorstsconfig
: path to the typescript configuration file used to provide behavior inspection and validationmetadata
: path to where the behaviors metadata will be placed (either full path to file or directory path)
Note: Values can be relative path values as long as they are relative to the directory containing the config file.
A default is provided for you and can be found in the root of the project <path to project>/behavior-config.yml
and is the config file this command looks for (in the current working directory) if one is supplied using the -c, --config
option.
When using the default config file this command can be used to build all behaviors using ./bin/cli behaviors -b
otherwise, you will need specify your own config ./bin/cli behaviors -c <path to your config> -b
For more details concerning the internals of the build process consult the documentation for the build system.
New behavior command
The newBehavior command provides a simple way to create a new behavior by generating a new file in the behavior directory containing the required boiler plate.
Executing ./bin/cli newBehavior awesomeBehavior
will create a new behavior file awesomeBehavior.js
located in the behavior directory.
The full options that are available are displayed below.
$ ./bin/cli newBehavior
Usage: cli-newBehavior [options] <behavior file name>
Options:
-V, --version output the version number
-d, --dir <directory name> The new behavior will be created in the supplied directory name within the behaviors directory
-h, --help output usage information
Runner command
The runner command allows you to automatically run a behavior on a specified URL using a Chrome/Chromium browser installed on your machine.
The full options that are available are displayed below.
$ ./bin/cli help runner
Usage: cli-runner [options] [path-to-behavior]
Options:
-V, --version output the version number
--build-config [behavior build config path] Path to the behavior config file (default: "<cwd>/behavior-config.yml")
-c, --config [run config path] Path to a behavior's run config file
-r, --run Builds and runs the behavior
-w, --watch Watches the behavior for changes rebuilding and running the behavior on change
--run-built Runs a previously built behavior
-s, --slowmo <amount> How much slow mo (delay) should be used between behavior steps
-t, --run-timeout <amount> Maximum amount of time a behavior will run
-e, --chromeEXE <chrome executable> The chrome executable to be launched rather than attempting to discover / choose the best version of chrome installed
-u, --url <url> URL of the page to run the behavior on
-h, --help output usage information
Please note that in order to provide automatic running of behaviors, this command must be able to launch the Chrome/Chromium browser. In other words, an already running instance of Chrome/Chromium can not be used.
The simplest way to use this command is through the usage of a config file (yaml format) and can be supplied using the -c
or --config
flags like so ./bin/cli runner -c <path to run config.yaml>
.
An example run config is provided for you and can found in the root of this project (behavior-run-config.yml).
The config file has seven keys and should specified in the config as key: value
buildConfig
(required): path to the behavior build configbehavior
(required): path to the behavior to be runurl
(required): the URL the behavior will be run onmode
(optional): The available modes arebuild-watch
: build and run the behavior, rebuilds and restarts the behavior on changes to the behaviorbuild
: build and run the behavior once (default mode)built
: just run the previously built behavior
chromeEXE
(optional): Chrome/Chromium executable path or command name to be used to launch (defaults to finding acceptable installed executable)timeout
(optional): time value in seconds indicating the maximum length of time the behavior will runslomo
(optional): time value in seconds indicating how long to wait before initiating the next action of the behavior
STDLIB command
The stdlib command exists as an utility for generating the provided behavior utility library's index.js
file or to create a bundle of all provided library function for debugging.
The file name of the generated debug script is libOnWindow.js
and is placed in root dir of the project.
The full options that are available are displayed below.
$ ./bin/cli help stdlib
Usage: cli-stdlib [options]
Options:
-V, --version output the version number
--gen-index Generate the behavior's standard library's index file
--debug-script Generate a script that exposes the entirety of the behavior's standard library on window
-h, --help output usage information
Pre-made Behaviors
Autoscroll
Applies to
Pages that do not have a predefined behavior for them
Behavior
Automatically scroll down the page and captures any embedded content. If more content loads, scrolling will continue until autopilot is stopped by user.
Specifics
The discovery of media is done by considering the rendered HTML of page at the current scroll position and the playing of the discovered media is done using operations defined for HTML media elements. If the page requires a more specific action to be performed in order to play its media, the behavior may fail to play the media and in this case, a more specific behavior should be made in order to handle this condition.
Gotchas
Instagram changes their CSS class names frequently which can potentially cause the behaviors to not be able to view/play media content until they are updated.
Video posts require application logic to be played consistently. Gifs are shown via the video element and actual videos are streamed.
Note data request politeness (1 img = 4 requests)
Stories
Requires the viewer to be logged in
Logged in state detected if the “logged-in” CSS class is present or the login/sign-up element are not present
User (not own feed)
Updated: 2019-07-15T22:29:05
Applies to
https://(www.)instagram.com/[user name](/)
https://(www.)instagram.com/[user name](/?query-string)
https://(www.)instagram.com/[user name](/tagged)(/)
Behavior
- View stories if able
- View each post currently visible
- If not stopping condition: wait for more rows indefinitely*
Viewing stories
As previously mentioned, a logged in user. If there are selected stories (profile picture is clickable) they are viewed first If there are normal stories to be viewed they are viewed
Viewing posts
Video post (gif, traditional video)
- video is played and a wait for the user agent to determine if the video can play through all the way is done
Photo post
- no “special” action other than view
Multiple media post
- each part of the multi-post is viewed
- if video media is contained the video post action is performed before moving to the next part
- otherwise photo post action is performed
All post types
- all comments and replies to comments are loaded
Stopping condition
Since instagram is a react application we attempt to extract the “redux store” in order to determine the number of posts by the user and to listen for application state changes that indicate if there are additional “pages” (more posts) to be retrieved.
If extraction of the “redux store” fails or application internals have changed we fall back to a rudimentary post counting scheme. When not using store the wait for more post rows to be rendered is limited to 1 minute
The completion condition can be expressed as follows Store extraction has not failed: There are no more pages to be retrieved and the current row of posts does not have a next sibling Store extraction failed: The number of posts viewed is >= number of posts by the user and the current row of posts does not have a next sibling
Individual Post
Applies to
https://(www.)instagram.com/p/[post-id](/)
Behavior The actions of this behavior are described in the Viewing posts section of the Instagram User behavior
Own Feed
Note: Requires logged in viewer
Unlike viewing of some other users posts the viewing of own feed posts is limited due to instagram not displaying the viewed post in a popup rather you are taken to post page
Applies to
https://(www.)instagram.com(/)
Behavior
View stories if any are to be had
For each rendered post:
- perform actions described in the Viewing posts section of the Instagram User behavior with one exception, comments cannot be viewed If stopping condition not met wait for more posts to be loaded at maximum 45 seconds
Stopping condition
The currently viewed post has no next sibling after 45 seconds
Gotchas
Tweet embeds although sometimes viewable inline by clicking on them are shown using an iframe that the behavior does not have access to
Audio video tweets are streamed and if the media is of significant length waiting for them to become fully loaded may take the entire length of the video or a significantly long period of time (5+ minutes)
Timeline
Applies to
https://(www.)twitter.com(/)
-- Note this requires logged inhttps://(www.)twitter.com/[user-name](/)
Behavior
If the viewed page is marked as sensitive, reveal page
For each rendered tweet
- If tweet marked as sensitive reveal it
- If tweet has video play it
Open tweet
- If tweet has replies or apart of thread view comments thread parts
If stopping condition is not met wait for more tweets to be loaded
Stopping condition
The currently viewed tweet does not have a sibling and the pre-rendered stream end or stream failed are made visible
HashTags
Applies to
https://(www.)twitter.com/hashtag/[hash-tag](remaining-URL-parts)*
Behavior
For each rendered tweet
- If tweet marked as sensitive reveal it
- If tweet has video play it
- Open tweet
- If tweet has replies or apart of thread view comments thread parts
If stopping condition is not met wait for more tweets to be loaded and repeat
Stopping condition
The currently viewed tweet does not have a sibling and the pre-rendered stream end or stream failed are made visible
Youtube Video
Applies to
- https://(www.)youtube.com/watch?v=[remaining-URL-parts]+
Behavior
Loads the videos additional information
Plays the video
Clicks show more replies until all replies have been loaded (if there were replies)