diff --git a/src/fetchers.ts b/src/fetchers.ts index 6b97e7d..abed59d 100644 --- a/src/fetchers.ts +++ b/src/fetchers.ts @@ -62,6 +62,17 @@ export const fetchComments = async (galleryID: string): Promise => { /* eslint-enable max-len */ } +export const fetchUserPosts = async (userID: string, sort: Sorting = 'newest'): Promise => { + /* eslint-disable max-len */ + // https://api.imgur.com/3/account/mombotnumber5/submissions/0/newest?album_previews=1&client_id=${CLIENT_ID} + const response = await got( + `https://api.imgur.com/3/account/${userID.toLowerCase()}/submissions/0/newest?album_previews=1&client_id=${CONFIG.imgur_client_id}`, + { agent } + ); + return JSON.parse(response.body).data; + /* eslint-enable max-len */ +} + export const fetchGallery = async (galleryID: string): Promise => { // https://imgur.com/gallery/g1bk7CB const response = await got(`https://imgur.com/gallery/${galleryID}`, { agent }); diff --git a/src/handlers.ts b/src/handlers.ts index 27c80ca..39fe571 100644 --- a/src/handlers.ts +++ b/src/handlers.ts @@ -1,6 +1,6 @@ import Hapi = require('@hapi/hapi'); import '@hapi/vision'; -import { fetchAlbum, fetchAlbumURL, fetchComments, fetchGallery, fetchMedia } from './fetchers'; +import { fetchAlbum, fetchAlbumURL, fetchComments, fetchGallery, fetchMedia, fetchUserPosts } from './fetchers'; import * as util from './util'; import CONFIG from './config'; @@ -35,9 +35,18 @@ export const handleAlbum = async (request: Hapi.Request, h: Hapi.ResponseToolkit }); }; -export const handleUser = (request: Hapi.Request, h: Hapi.ResponseToolkit) => { +export const handleUser = async (request: Hapi.Request, h: Hapi.ResponseToolkit) => { // https://imgur.com/user/MomBotNumber5 - throw new Error('not implemented'); + if (!CONFIG.use_api) { + return 'User page disabled. Rimgu administrator needs to enable API for this to work.'; + } + const userID = request.params.userID; + const userPosts = await fetchUserPosts(userID); + return h.view('user-posts', { + userPosts, + pageTitle: CONFIG.page_title, + util, + }); }; export const handleTag = (request: Hapi.Request, h: Hapi.ResponseToolkit) => { diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 9a835cd..fafd587 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -8,6 +8,7 @@ interface Account { type MediaMimeType = 'image/jpeg' | 'image/png' | 'image/gif'; type MediaType = 'image'; type MediaExt = 'jpeg' | 'png' | 'gif'; +type Sorting = 'newest' | 'oldest' | 'best'; interface Tag { tag: string; diff --git a/static/css/styles.css b/static/css/styles.css index 9c02d17..9b88451 100644 --- a/static/css/styles.css +++ b/static/css/styles.css @@ -290,4 +290,102 @@ a { text-transform: uppercase; color: #dadce2; flex-grow: 1; +} + + +/* USER POSTS */ +.ProfilePost { + width: 320px; + display: inline-block; + margin: 0 8px; +} + +.Post-item { + /* height: 100%; */ + display: block; + margin-bottom: 30px; + background-repeat: no-repeat; + cursor: pointer; + background-size: 145px; + position: relative; + color: #fff; + box-shadow: 0 2px 4px 0 rgba(0,0,0,.4); + background-color: #2e3035; + transition: box-shadow .25s; + -webkit-transition: box-shadow .25s; +} + +.Post-item-container { + /* height: 100%; */ + position: relative; + overflow: hidden; + border-radius: 3px; +} + +.Post-item-media { + overflow: hidden; +} + +.Post-item-meta { + position: absolute; + top: 15px; + right: 15px; + left: 15px; + font-size: 12px; + line-height: 16px; +} + +.Post-item-media img { + width: 100%; +} + +.Post-item-info, .PostInfo { + display: flex; + align-items: center; + font-size: 12px; + line-height: 1.5; + letter-spacing: .3px; +} + +.Post-item-info { + justify-content: space-between; + color: hsla(0,0%,100%,.6); + min-height: 8px; + padding: .5rem 1rem; + color: #b4b9c2; +} + +Post-item-title { + font-weight: 600; + line-height: 1.14; + font-size: 14px; + text-align: left; + color: #fff; + display: inline-block; + max-height: 45px; + overflow: hidden; + padding: 0 15px; +} + +.Media { + display: flex; + flex-direction: row; + align-items: center; +} + +.Post-item-stat { + z-index: 1; + opacity: .65; +} + +.MediaBody { + margin: 0 .25rem; +} + +.Post-item-media .imageContainer { + max-height: 500px; +} + +.Post-item-media .PostVideo { + max-height: 500px; } \ No newline at end of file diff --git a/templates/user-posts.pug b/templates/user-posts.pug new file mode 100644 index 0000000..953a96e --- /dev/null +++ b/templates/user-posts.pug @@ -0,0 +1,50 @@ +html + head + include includes/head.pug + body + .Profile + .App-cover.NewCover.ProfileCover + .ProfilePosts-posts + .ProfilePosts-top + each post in userPosts + div.ProfilePost + a.Post-item.novote(href="/gallery/"+post.id) + .Post-item-container + .Post-item-media + if post.images && post.images[0].animated + .PostVideo + .PostVideo-video-wrapper + video(playsinline autoplay loop mute) + source(type="video/mp4" src=util.proxyURL(post.images[0].mp4)) + else + .imageContainer + img(src=util.proxyURL(post.images ? post.images[0].link : post.link) loading="lazy") + .Post-item-meta + .Post-item-title-wrap + .Post-item-title + span= post.title + .Post-item-info + .Media + div(class='Post-item-stat Post-item-vote' title='Upvotes') + div(class='Vote Vote-up') + svg(width='16', height='16', viewBox='0 0 16 16', fill='none', xmlns='http://www.w3.org/2000/svg') + title Upvotes + | + .points= post.points + div(class='Post-item-stat Post-item-vote' title='Downvotes') + div(class='Vote Vote-down') + svg(width='16', height='16', viewBox='0 0 16 16', fill='none', xmlns='http://www.w3.org/2000/svg') + title Downvotes + | + .Media.Post-item-stat + svg(width="16" height="16" viewBox="0 0 16 16" class="PostCommentsIcon" fill="none" xmlns="http://www.w3.org/2000/svg") + title Comments + | + .MediaBody= post.comment_count + .Media.Post-item-stat + svg(width="16" height="16" viewBox="0 0 16 16" class="PostViewsIcon" fill="none" xmlns="http://www.w3.org/2000/svg") + title Post views + | + .MediaBody= post.views + +