diff --git a/.gitignore b/.gitignore index 5dd477f..3f0d495 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,7 @@ #ignore system files .DS_Store + +#bootstrap slim +assets/bootstrap/* +!assets/bootstrap/css/bootstrap.min.css +!assets/bootstrap/css/bootstrap.min.css.map diff --git a/assets/peertube.css b/assets/peertube.css index a229e1e..b139840 100644 --- a/assets/peertube.css +++ b/assets/peertube.css @@ -9,293 +9,148 @@ will-change: transform; } -.status { - padding: 8px 10px 8px 68px; - position: relative; - min-height: 54px; - border-bottom: 1px solid #c0cdd9; - cursor: default; - opacity: 1; - -webkit-animation: fade .15s linear; - animation: fade .15s linear; +.peertube-timeline__header { + width: 100vw; + overflow-x: auto; + padding-left: 15px; + padding-right: 15px; + margin-bottom: 10px; } -.status__prepend { - margin-left: 68px; - color: #444b5d; - padding: 8px 0 2px; - font-size: 14px; - position: relative; -} -.status__prepend-icon-wrapper { - left: -26px; - position: absolute; -} -.fa-fw { - width: 1.28571429em; - text-align: center; -} -.fa { - display: inline-block; -} -.account__header { - overflow: hidden; -} -.account__header__image { - overflow: hidden; - height: 145px; - position: relative; - background: #e6ebf0; -} -.account__header__info { - position: absolute; - top: 10px; - left: 10px; -} -.account__header__image img { - object-fit: cover; - display: block; +.actor, +.actor-info { width: 100%; - height: 100%; - margin: 0; } -.account__header__bar { - position: relative; - background: #fff; - padding: 5px; - border-bottom: 1px solid #b3c3d1; -} -.account__header__tabs { +.actor { + display: -webkit-box; display: flex; - align-items: flex-start; - padding: 7px 5px; - margin-top: -55px; + margin-top: 20px; + margin-bottom: 20px; } -.account__header__bar .avatar { - display: block; - flex: 0 0 auto; - width: 94px; - margin-left: -2px; -} -.account__header__tabs .spacer { - flex: 1 1 auto; -} -.account__header__tabs__buttons .button { - margin: 0 8px; - color: #fff; - border-radius: 4px; - padding: 0px 16px; - height: 36px; - line-height: 36px; -} -.account__header__tabs__name { - padding: 5px; -} -.account__header__tabs__name h1 { - font-size: 16px; - line-height: 24px; - color: #000; - font-weight: 500; - margin: 0; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} -.account__header__tabs__name h1 small { - display: block; - font-size: 14px; - color: #282c37; - font-weight: 400; - overflow: hidden; - text-overflow: ellipsis; -} -.account__header__extra { - margin-top: 4px; -} -.account__header__bio { - overflow: hidden; - margin: 0 -5px; -} -.account__header__bio .account__header__content { - padding: 20px 15px 5px; - color: #000; -} -.account__header__content { - color: #282c37; - font-size: 14px; - font-weight: 400; - overflow: hidden; - word-break: normal; - word-wrap: break-word; -} -.account__display-name, -.detailed-status__application, -.detailed-status__datetime, -.detailed-status__display-name, -.status__display-name, -.status__relative-time { - text-decoration: none; -} -.status__display-name { - color: #444b5d; -} -.status__expand { - width: 68px; - position: absolute; - left: 0; - top: 0; - height: 100%; - cursor: pointer; -} -.status__info { - font-size: 15px; -} -.status__info .status__display-name { - display: block; - max-width: 100%; - padding-right: 25px; -} -.status__avatar { - height: 48px; - left: 10px; - position: absolute; - top: 10px; - width: 48px; -} -.account__avatar { - border-radius: 4px; - background: transparent no-repeat; - background-position: 50%; - background-clip: padding-box; - position: relative; -} -.account__avatar-overlay { - width: 48px; - height: 48px; - background-size: 48px 48px; -} -.account__avatar-overlay-base { - border-radius: 4px; - background: transparent no-repeat; - background-position: 50%; - background-clip: padding-box; - width: 36px; - height: 36px; - background-size: 36px 36px; -} -.account__avatar-overlay-overlay { - border-radius: 4px; - background: transparent no-repeat; - background-position: 50%; - background-clip: padding-box; - width: 24px; - height: 24px; - background-size: 24px 24px; - position: absolute; - bottom: 0; - right: 0; - z-index: 1; -} -.display-name { - display: block; - max-width: 100%; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.display-name__account { - font-size: 14px; -} -.account__display-name strong, .status__display-name strong { - color: #000; -} -.display-name__html { - font-weight: 500; -} -.notification__relative_time, .status__relative-time { - color: #444b5d; - float: right; - font-size: 14px; -} -.status-card.compact { - border-color: #ccd7e0; -} -.status-card { - display: flex; - font-size: 14px; - border: 1px solid #c0cdd9; - border-radius: 4px; - color: #444b5d; - margin-top: 14px; - text-decoration: none; - overflow: hidden; - cursor: pointer; -} -.status-card.compact .status-card__image { - flex: 0 0 60px; -} -.status-card__image { - flex: 0 0 100px; - background: #c0cdd9; - position: relative; -} -.status-card__image-image { - border-radius: 4px 0 0 4px; - display: block; - margin: 0; - width: 100%; - height: 100%; +.actor img { + -o-object-fit: cover; object-fit: cover; - background-size: cover; - background-position: 50%; + border-radius: 50%; + width: 80px; + height: 80px; + min-width: 80px; + margin-right: 20px; } -.status-card.compact .status-card__content { - padding: 10px 8px 8px; +.actor .actor-info { + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + -webkit-box-pack: center; + justify-content: center; } -.status-card__content { - flex: 1 1 auto; - overflow: hidden; - padding: 14px 14px 14px 8px; +.actor .actor-display-link { + text-decoration: none; } -.status-card__title { - display: block; - font-weight: 500; +.actor .actor-info .actor-names .actor-display-name { + font-size: 23px; + font-weight: 700; +} +.actor-info .actor-names .actor-name { + margin-left: 7px; + position: relative; + top: 3px; + font-size: 14px; + color: #777272; +} +.video { margin-bottom: 1.5em; } +.videos .video-miniature { + padding-right: 0; + height: auto; + width: 100%; margin-bottom: 5px; - color: #282c37; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - text-decoration: none; } -.status-card__description { - color: #282c37; -} -.status-card__host { - display: block; - margin-top: 5px; - font-size: 13px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} -.status__content summary { - background: #eee; - border-radius: 5px; - padding: 2px 8px; - cursor: pointer; - display: inline-block; -} -.status__content .media-gallery__item{ - margin: 1em 0; -} -i.fa-retweet { - background-image: url('../img/retoot.svg'); - background-position: 0 0; - height: 19px; - vertical-align: middle; - width: 22px; - color: #ccc; - opacity: .75; - z-index: 10; +.video-thumbnail { + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; position: relative; + border-radius: 3px; + overflow: hidden; + background-color: #ececec; + -webkit-transition: -webkit-filter .2s; + transition: -webkit-filter .2s ease; + transition: filter .2s ease; + transition: filter .2s ease,-webkit-filter .2s ease; +} +.videos .video-miniature .video-thumbnail { + margin: 0; + width: 100%; + height: auto; + border-radius: 0; +} +.videos .video-miniature .video-thumbnail img { + width: 100%; + height: auto; +} +.video-thumbnail .play-overlay { + position: absolute; + right: 0; + bottom: 0; + width: inherit; + height: inherit; + opacity: 0; + background-color: rgba(0,0,0,.7); +} +.video-thumbnail .play-overlay, +.video-thumbnail .play-overlay .icon { + -webkit-transition: .2s; + transition: all .2s ease; +} +.video-thumbnail .play-overlay .icon { + width: 0; + height: 0; + position: absolute; + left: 50%; + top: 50%; + -webkit-transform: translate(-50%,-50%) scale(.5); + transform: translate(-50%,-50%) scale(.5); + border-top: 13px solid transparent; + border-bottom: 13px solid transparent; + border-left: 18px solid rgba(255,255,255,.95); +} +.video-miniature .video-bottom { + display: -webkit-box; + display: flex; +} +.video-thumbnail .video-thumbnail-duration-overlay { + display: inline-block; + background-color: rgba(0,0,0,.7); + color: #fff; + position: absolute; + right: 5px; + bottom: 5px; + padding: 0 5px; + border-radius: 3px; + font-size: 12px; + font-weight: 700; +} +.video-miniature-name{ +font-weight: 600; + margin: 0 0 5px; + text-decoration: none; + text-overflow: ellipsis; +} + +.video-miniature-created-at-views { + font-size: 0.75em; +} +.video-miniature-created-at-views .views::before { + content: ' - ' +} +.video-miniature-account { + hite-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + display: block; + font-size: 0.75em; + color: #585858; } diff --git a/fediembedi-client.php b/fediembedi-client.php index 2392a20..7fec66c 100644 --- a/fediembedi-client.php +++ b/fediembedi-client.php @@ -48,25 +48,25 @@ class FediClient return $this->instance_url.'/oauth/authorize?'.$params; } - public function register_client($redirect_uri, $scopes = 'read') { - - $response = $this->_get('/api/v1/oauth-clients/local'); - - if (!isset($response->client_id)){ - return "ERROR"; - } - - $this->app = $response; - - $params = http_build_query(array( - 'scope' => $scopes, - 'client_id' =>$this->app->client_id, - 'client_secret' =>$this->app->client_secret - )); - - $access_token = $this->_post('/api/v1/oauth-clients/local'); -// return $this->instance_url.'/users/token?'.$params; - } +// public function register_client($redirect_uri, $scopes = 'read') { +// +// $response = $this->_get('/api/v1/oauth-clients/local'); +// +// if (!isset($response->client_id)){ +// return "ERROR"; +// } +// +// $this->app = $response; +// +// $params = http_build_query(array( +// 'scope' => $scopes, +// 'client_id' =>$this->app->client_id, +// 'client_secret' =>$this->app->client_secret +// )); +// +// $access_token = $this->_post('/api/v1/oauth-clients/local'); +// // return $this->instance_url.'/users/token?'.$params; +// } public function verify_credentials($access_token){ @@ -138,26 +138,15 @@ class FediClient return $response; } - public function getVideos($media = 'false', $pinned = 'false', $replies = 'false', $max_id = null, $since_id = null, $min_id = null, $limit = 10, $reblogs = 'false') { + public function getVideos($account_id, $is_channel) { - $headers = array( - 'Authorization'=> 'Bearer '.$this->access_token - ); + $headers = array(); - $account_id = self::$acct_id; - - // $query = http_build_query(array( - // 'only_media' => $media, - // 'pinned' => $pinned, - // 'exclude_replies' => $replies, - // 'max_id' => $max_id, - // 'since_id' => $since_id, - // 'min_id' => $min_id, - // 'limit' => $limit, - // 'exclude_reblogs' => $reblogs - // )); - - $response = $this->_get("/api/v1/accounts/{$account_id}/videos", null, $headers); + if(!is_null($is_channel)){ + $response = $this->_get("/api/v1/video-channels/{$account_id}/videos", null, $headers); + } else { + $response = $this->_get("/api/v1/accounts/{$account_id}/videos", null, $headers); + } return $response; } diff --git a/fediembedi-mastodon-widget.php b/fediembedi-mastodon-widget.php new file mode 100644 index 0000000..b3bb95c --- /dev/null +++ b/fediembedi-mastodon-widget.php @@ -0,0 +1,178 @@ + 'mastodon_widget', + 'description' => __( 'Display a profile timeline', 'fediembedi' ), + 'customize_selective_refresh' => true, + ); + parent::__construct( 'mastodon', _x( 'Mastodon', 'fediembedi' ), $widget_ops ); + } + + /** + * Outputs the content for the current Search widget instance. + * + * @since 2.8.0 + * + * @param array $args Display arguments including 'before_title', 'after_title', + * 'before_widget', and 'after_widget'. + * @param array $instance Settings for the current Search widget instance. + */ + public function widget( $args, $instance ) { + $title = ! empty( $instance['title'] ) ? $instance['title'] : ''; + + //fedi instance + $fedi_instance = get_option('fediembedi-mastodon-instance'); + $access_token = get_option('fediembedi-mastodon-token'); + $client = new \FediClient($fedi_instance, $access_token); + $cred = $client->verify_credentials($access_token); + + //widget options + $show_header = (!empty($instance['show_header'])) ? $instance['show_header'] : ''; + $only_media = (!empty($instance['only_media'])) ? $instance['only_media'] : ''; + $pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : ''; + $exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : ''; + $exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : ''; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : '100%'; + + //if(WP_DEBUG_DISPLAY === true): echo '
'. $instance_type .'
'; var_dump($status); echo '
'; endif; + + echo $args['before_widget']; + if ( $title ) { + echo $args['before_title'] . $title . $args['after_title']; + }; + + //getStatus from remote instance + $status = $client->getStatus($only_media, $pinned, $exclude_replies, null, null, null, $number, $exclude_reblogs); + include(plugin_dir_path(__FILE__) . 'templates/mastodon.tpl.php' ); + + echo $args['after_widget']; + } + + /** + * Outputs the settings form for the Search widget. + * + * @since 2.8.0 + * + * @param array $instance Current settings. + */ + public function form( $instance ) { + $instance = wp_parse_args( (array) $instance, array( 'title' => '') ); + //Radio inputs : https://wordpress.stackexchange.com/a/276659/87622 + $show_header = (!empty( $instance['show_header'])) ? $instance['show_header'] : NULL; + $only_media = (!empty( $instance['only_media'])) ? $instance['only_media'] : NULL; + $pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : NULL; + $exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : NULL; + $exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : NULL; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : ''; + + ?> +

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ '' ) ); + $instance['title'] = sanitize_text_field( $new_instance['title'] ); + $instance['show_header'] = $new_instance['show_header']; + $instance['only_media'] = $new_instance['only_media']; + $instance['pinned'] = $new_instance['pinned']; + $instance['exclude_replies'] = $new_instance['exclude_replies']; + $instance['exclude_reblogs'] = $new_instance['exclude_reblogs']; + $instance['number'] = (int) $new_instance['number']; + $instance['height'] = sanitize_text_field( $new_instance['height'] ); + return $instance; + } + +} diff --git a/fediembedi-peertube-widget.php b/fediembedi-peertube-widget.php new file mode 100644 index 0000000..5a22db4 --- /dev/null +++ b/fediembedi-peertube-widget.php @@ -0,0 +1,164 @@ + 'peertube_widget', + 'description' => __( 'Display a profile timeline', 'fediembedi' ), + 'customize_selective_refresh' => true, + ); + parent::__construct( 'peertube', _x( 'PeerTube', 'fediembedi' ), $widget_ops ); + } + + /** + * Outputs the content for the current Search widget instance. + * + * @since 2.8.0 + * + * @param array $args Display arguments including 'before_title', 'after_title', + * 'before_widget', and 'after_widget'. + * @param array $instance Settings for the current Search widget instance. + */ + public function widget( $args, $instance ) { + $title = ! empty( $instance['title'] ) ? $instance['title'] : ''; + + //fedi instance + $fedi_instance = (!empty($instance['peertube'])) ? $instance['peertube'] : ''; + $actor = (!empty($instance['actor'])) ? $instance['actor'] : ''; + $is_channel = (!empty($instance['channel'])) ? $instance['channel'] : null;//radio channel or account + + $client = new \FediClient($fedi_instance); + + //widget options + $show_header = (!empty($instance['show_header'])) ? $instance['show_header'] : null; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : '100%'; + + echo $args['before_widget']; + if ( $title ) { + echo $args['before_title'] . $title . $args['after_title']; + }; + + //getVideos from remote instance + $status = $client->getVideos($actor, $is_channel); + if(!is_null($is_channel)){ + $account = $status->data[0]->channel; + } else { + $account = $status->data[0]->account; + } + if(WP_DEBUG_DISPLAY === true): echo '
PeerTube
'; var_dump($status); echo '
'; endif; + include(plugin_dir_path(__FILE__) . 'templates/peertube.tpl.php' ); + + echo $args['after_widget']; + } + + /** + * Outputs the settings form for the Search widget. + * + * @since 2.8.0 + * + * @param array $instance Current settings. + */ + public function form( $instance ) { + $instance = wp_parse_args( (array) $instance, array( 'title' => '') ); + //Radio inputs : https://wordpress.stackexchange.com/a/276659/87622 + + $peertube = (!empty($instance['peertube'])) ? $instance['peertube'] : NULL; + $actor = (!empty($instance['actor'])) ? $instance['actor'] : NULL; + $is_channel = (!empty($instance['channel'])) ? $instance['channel'] : NULL; + + $show_header = (!empty( $instance['show_header'])) ? $instance['show_header'] : NULL; + $only_media = (!empty( $instance['only_media'])) ? $instance['only_media'] : NULL; + $pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : NULL; + $exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : NULL; + $exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : NULL; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : ''; + + ?> +

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ '' ) ); + $instance['title'] = sanitize_text_field( $new_instance['title'] ); + $instance['peertube'] = esc_url($new_instance['peertube']); + $instance['actor'] = sanitize_key($new_instance['actor']); + $instance['channel'] = $new_instance['channel']; + $instance['show_header'] = $new_instance['show_header']; + $instance['only_media'] = $new_instance['only_media']; + $instance['pinned'] = $new_instance['pinned']; + $instance['exclude_replies'] = $new_instance['exclude_replies']; + $instance['exclude_reblogs'] = $new_instance['exclude_reblogs']; + $instance['number'] = (int) $new_instance['number']; + $instance['height'] = sanitize_text_field( $new_instance['height'] ); + return $instance; + } + +} diff --git a/fediembedi-pixelfed-widget.php b/fediembedi-pixelfed-widget.php new file mode 100644 index 0000000..7ee8037 --- /dev/null +++ b/fediembedi-pixelfed-widget.php @@ -0,0 +1,177 @@ + 'pixelfed_widget', + 'description' => __( 'Display a profile timeline', 'fediembedi' ), + 'customize_selective_refresh' => true, + ); + parent::__construct( 'pixelfed', _x( 'Pixelfed', 'fediembedi' ), $widget_ops ); + } + + /** + * Outputs the content for the current Search widget instance. + * + * @since 2.8.0 + * + * @param array $args Display arguments including 'before_title', 'after_title', + * 'before_widget', and 'after_widget'. + * @param array $instance Settings for the current Search widget instance. + */ + public function widget( $args, $instance ) { + $title = ! empty( $instance['title'] ) ? $instance['title'] : ''; + + //fedi instance + $instance_url = get_option('fediembedi-pixelfed-instance'); + $access_token = get_option('fediembedi-pixelfed-token'); + $client = new \FediClient($instance_url, $access_token); + $cred = $client->verify_credentials($access_token); + + //widget options + $show_header = (!empty($instance['show_header'])) ? $instance['show_header'] : ''; + $only_media = (!empty($instance['only_media'])) ? $instance['only_media'] : ''; + $pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : ''; + $exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : ''; + $exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : ''; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : '100%'; + + //if(WP_DEBUG_DISPLAY === true): echo '
'. $instance_type .'
'; var_dump($status); echo '
'; endif; + + echo $args['before_widget']; + if ( $title ) { + echo $args['before_title'] . $title . $args['after_title']; + }; + + $status = $client->getStatus($only_media, $pinned, $exclude_replies, null, null, null, $number, $exclude_reblogs); + include(plugin_dir_path(__FILE__) . 'templates/pixelfed.tpl.php' ); + + echo $args['after_widget']; + } + + /** + * Outputs the settings form for the Search widget. + * + * @since 2.8.0 + * + * @param array $instance Current settings. + */ + public function form( $instance ) { + $instance = wp_parse_args( (array) $instance, array( 'title' => '') ); + //Radio inputs : https://wordpress.stackexchange.com/a/276659/87622 + $show_header = (!empty( $instance['show_header'])) ? $instance['show_header'] : NULL; + $only_media = (!empty( $instance['only_media'])) ? $instance['only_media'] : NULL; + $pinned = (!empty($instance['pinned'])) ? $instance['pinned'] : NULL; + $exclude_replies = (!empty($instance['exclude_replies'])) ? $instance['exclude_replies'] : NULL; + $exclude_reblogs = (!empty($instance['exclude_reblogs'])) ? $instance['exclude_reblogs'] : NULL; + $number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5; + $height = isset( $instance['height'] ) ? esc_attr( $instance['height'] ) : ''; + + ?> +

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+

+ +

+ '' ) ); + $instance['title'] = sanitize_text_field( $new_instance['title'] ); + $instance['show_header'] = $new_instance['show_header']; + $instance['only_media'] = $new_instance['only_media']; + $instance['pinned'] = $new_instance['pinned']; + $instance['exclude_replies'] = $new_instance['exclude_replies']; + $instance['exclude_reblogs'] = $new_instance['exclude_reblogs']; + $instance['number'] = (int) $new_instance['number']; + $instance['height'] = sanitize_text_field( $new_instance['height'] ); + return $instance; + } + +} diff --git a/fediembedi-settings-form.tpl.php b/fediembedi-settings-form.tpl.php index c5999d3..afc59eb 100644 --- a/fediembedi-settings-form.tpl.php +++ b/fediembedi-settings-form.tpl.php @@ -1,43 +1,68 @@ - -

-
-
-
+

-
"> - - - -

-

-

Visit joinmastodon.org to find an instance.

-

Visit pixelfed.org/join to find an instance.

-
-
"> -