aboutsummaryrefslogtreecommitdiffstats
path: root/youtube
diff options
context:
space:
mode:
Diffstat (limited to 'youtube')
-rw-r--r--youtube/static/channel.css557
-rw-r--r--youtube/static/comments.css359
-rw-r--r--youtube/static/dark_theme.css54
-rw-r--r--youtube/static/gray_theme.css33
-rw-r--r--youtube/static/home.css197
-rw-r--r--youtube/static/light_theme.css34
-rw-r--r--youtube/static/local_playlist.css527
-rw-r--r--youtube/static/normalize.css349
-rw-r--r--youtube/static/playlist.css537
-rw-r--r--youtube/static/search.css495
-rw-r--r--youtube/static/settings.css241
-rw-r--r--youtube/static/subscription.css530
-rw-r--r--youtube/static/subscription_manager.css403
-rw-r--r--youtube/static/watch.css633
-rw-r--r--youtube/templates/base.html397
-rw-r--r--youtube/templates/channel.html143
-rw-r--r--youtube/templates/comments.html21
-rw-r--r--youtube/templates/comments_page.html10
-rw-r--r--youtube/templates/common_elements.html67
-rw-r--r--youtube/templates/error.html7
-rw-r--r--youtube/templates/home.html11
-rw-r--r--youtube/templates/local_playlist.html36
-rw-r--r--youtube/templates/local_playlists_list.html21
-rw-r--r--youtube/templates/playlist.html76
-rw-r--r--youtube/templates/search.html61
-rw-r--r--youtube/templates/settings.html79
-rw-r--r--youtube/templates/subscription_manager.html78
-rw-r--r--youtube/templates/subscriptions.html81
-rw-r--r--youtube/templates/watch.html905
29 files changed, 5432 insertions, 1510 deletions
diff --git a/youtube/static/channel.css b/youtube/static/channel.css
new file mode 100644
index 0000000..467bb0d
--- /dev/null
+++ b/youtube/static/channel.css
@@ -0,0 +1,557 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.author-container {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+ grid-template-areas:
+ "author"
+ "summary"
+ "subscribe";
+}
+.author {
+ grid-area: author;
+ display: grid;
+ grid-template-columns: 100px 1fr;
+ grid-column-gap: 1rem;
+ align-items: center;
+ justify-self: center;
+}
+.summary { grid-area: summary; }
+.summary p {
+ text-align: center;
+}
+.subscribe {
+ grid-area: subscribe;
+ justify-self: center;
+}
+.subscribe .btn-subscribe {
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ text-shadow: none;
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ border: none;
+ border-radius: 0.2rem;
+}
+
+/* Video list item */
+.video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.item-video.channel-item {
+ border-radius: 50%;
+ width: 150px;
+ height: 150px;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.playlist-item .thumbnail-info {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ height: 100%;
+ width: 50%;
+ text-align: center;
+ white-space: pre-line;
+ opacity: .8;
+ color: var(--text);
+ font-size: 0.8125rem;
+ background: var(--secondary-background);
+ padding: 0;
+}
+
+.playlist-item .thumbnail-info span {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ text-transform: none;
+}
+
+.thumbnail-img {
+ margin: auto;
+ display: block;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.info-box {
+ grid-area: info-box;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto auto auto auto;
+ grid-gap: 1px;
+ grid-template-areas:
+ "."
+ "."
+ "."
+ "."
+ ".";
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+.horizontal-stats {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.horizontal-stats > li {
+ display: inline;
+}
+
+.horizontal-stats > li:first-child::after {
+ content: " | ";
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ .author-container {
+ max-width: 50vw;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/comments.css b/youtube/static/comments.css
index b177a4f..080810e 100644
--- a/youtube/static/comments.css
+++ b/youtube/static/comments.css
@@ -1,148 +1,283 @@
-.video-metadata{
- display: grid;
- grid-template-columns: auto 1fr;
- grid-template-rows: auto auto 1fr auto;
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
}
- .video-metadata > .video-metadata-thumbnail-box{
- grid-row: 1 / span 3;
- }
- .video-metadata > .title{
- word-wrap:break-word;
- grid-row: 1;
- }
- .video-metadata > h2{
- grid-row: 2;
- font-size: 0.875rem;
- }
- .video-metadata > span{
- grid-row:3;
- }
- .video-metadata > hr{
- grid-row: 4;
- grid-column: 1 / span 2;
- width: 100%;
- }
-.comment-form{
+body {
display: grid;
- align-content: start;
- justify-items: start;
- align-items: start;
-}
- #comment-account-options{
- display:grid;
- grid-auto-flow: column;
- grid-column-gap: 10px;
- margin-top:10px;
- margin-bottom:10px;
- }
- #comment-account-options a{
- margin-left:10px;
- }
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
-.comments-area{
- display:grid;
+h1, h2, h3, h4, h5, h6, div, button {
+ margin: 0;
+ padding: 0;
+}
+
+img {
+ width: 100%;
+ height: auto;
}
- .comments-area textarea{
- resize: vertical;
- justify-self:stretch;
- }
- .post-comment-button{
- margin-top:10px;
- justify-self:end;
- }
- .comment-links{
- display:grid;
- grid-auto-flow: column;
- grid-column-gap: 10px;
- justify-content:start;
- }
-.comments{
- margin-top:10px;
- grid-row-gap: 10px;
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ border-radius: 5px;
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
display: grid;
- align-content:start;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form";
+ grid-area: header;
}
-.comment{
- display:grid;
- grid-template-columns: auto auto 100px 1fr;
- grid-template-rows: 0fr 0fr 0fr 0fr;
- background-color: var(--interface-color);
- justify-content: start;
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
}
-.comment .author-avatar{
- grid-column: 1;
- grid-row: 1 / span 3;
- align-self: start;
- margin-right: 5px;
- height:32px;
- width:32px;
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
}
- .comment .author-avatar-img{
- max-height: 100%;
- }
-.comment address{
- grid-column: 2;
- grid-row: 1;
- margin-right:15px;
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
white-space: nowrap;
- overflow:hidden;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
}
-.comment .text{
- grid-column: 2 / span 3;
- grid-row: 2;
- white-space: pre-wrap;
- min-width: 0;
- word-wrap: break-word;
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
}
+.dropdown-label {
+ grid-area: dropdown-label;
-.comment .permalink{
- grid-column: 3;
- grid-row: 1;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
}
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
-.comment .likes{
- grid-column:2;
- grid-row:3;
- font-weight:bold;
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
white-space: nowrap;
}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ margin: 0 auto;
+ max-width: 80ch;
+}
+
+/* comments */
+.comments-area {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.comments-area textarea {
+ resize: vertical;
+}
-.comment .bottom-row{
- grid-column:2 / span 3;
- grid-row:4;
- justify-self:start;
+.video-metadata {
display: grid;
- grid-auto-flow: column;
- grid-column-gap: 10px;
+ grid-template-columns: auto 1fr;
+ grid-column-gap: 0.5rem;
+ grid-template-rows: auto auto 1fr auto;
+ grid-template-areas:
+ "video-metadata-thumbnail-box ."
+ "video-metadata-thumbnail-box ."
+ "video-metadata-thumbnail-box .";
+}
+
+.video-metadata > h2 {
+ font-size: 0.875rem;
}
-details.replies > summary{
- background-color: var(--interface-color);
- border-style: outset;
- border-width: 1px;
- font-weight: bold;
- padding-bottom: 0px;
+.video-metadata-thumbnail-box {
+ grid-area: video-metadata-thumbnail-box;
}
-.replies-open-new-tab{
- display: inline-block;
- margin-top: 5px;
+.comment-form {
+ display: grid;
+ grid-row-gap: 0.5rem;
}
-details.replies .comment{
- width: 600px;
+.post-comment-button {
+ justify-self: end;
}
-.more-comments{
- justify-self:center;
- margin-top:10px;
+.comments {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.comment {
+ display: grid;
+ grid-template-columns: repeat(3, auto) 3fr;
+ grid-template-rows: repeat(4, auto);
+ grid-column-gap: 0.4rem;
+ grid-template-areas:
+ "author-avatar author-name permalink permalink"
+ "author-avatar comment-text comment-text comment-text"
+ ". comment-likes comment-likes comment-likes"
+ ". button-row button-row button-row";
+ background: var(--secondary-background);
+}
+
+.author-avatar { grid-area: author-avatar; }
+.author-name { grid-area: author-name; }
+.permalink { grid-area: permalink; }
+.comment-text { grid-area: comment-text; }
+.comment-likes { grid-area: comment-likes; }
+.button-row { grid-area: button-row; }
+
+.more-comments {
+ justify-self: center;
+ margin-top: 10px;
margin-bottom: 10px;
+ background: var(--secondary-background);
+ padding: 5px;
+
+ /* disable text selection */
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 780px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+ position: absolute;
+ }
}
diff --git a/youtube/static/dark_theme.css b/youtube/static/dark_theme.css
index 221dc95..bc14f5c 100644
--- a/youtube/static/dark_theme.css
+++ b/youtube/static/dark_theme.css
@@ -1,39 +1,17 @@
-body{
- --interface-color: #333333;
- --text-color: #cccccc;
- --background-color: #000000;
- --video-background-color: #080808;
+:root {
+ --background: #121212;
+ --text: #FFF;
+ --secondary-hover: #73828c;
+ --secondary-focus: #616161;
+ --secondary-inverse: #FFF;
+ --secondary-background: #424242;
+ --link: #22aaff;
+ --link-visited: #7755ff;
+ --buttom: #dcdcdb;
+ --buttom-text: #415462;
+ --button-border: #91918c;
+ --buttom-hover: #BBB;
+ --search-text: #FFF;
+ --time-background: #000;
+ --time-text: #FFF;
}
-
-a:link {
- color: #22aaff;
-}
-
-a:visited {
- color: #7755ff;
-}
-
-a:not([href]){
- color: var(--text-color);
-}
-
-.comment .permalink{
- color: #ffffff;
-}
-
-.setting-item{
- background-color: #444444;
-}
-
-
-.muted{
- background-color: #111111;
- color: gray;
-}
-
-.muted a:link {
- color: #10547f;
-}
-
-
-
diff --git a/youtube/static/gray_theme.css b/youtube/static/gray_theme.css
index ca699c7..cae689d 100644
--- a/youtube/static/gray_theme.css
+++ b/youtube/static/gray_theme.css
@@ -1,18 +1,17 @@
-body{
- --interface-color: #dadada;
- --text-color: #222222;
- --background-color: #bcbcbc;
- --video-background-color: #dadada;
-}
-
-.comment .permalink{
- color: #000000;
-}
-
-.setting-item{
- background-color: #eeeeee;
-}
-
-.muted{
- background-color: #888888;
+:root {
+ --background: #2d3743;
+ --text: #FFF;
+ --secondary-hover: #73828c;
+ --secondary-focus: rgba(115, 130, 140, 0.125);
+ --secondary-inverse: #FFF;
+ --secondary-background: #102027;
+ --link: #22aaff;
+ --link-visited: #7755ff;
+ --buttom: #dcdcdb;
+ --buttom-text: #415462;
+ --button-border: #91918c;
+ --buttom-hover: #BBB;
+ --search-text: #FFF;
+ --time-background: #000;
+ --time-text: #FFF;
}
diff --git a/youtube/static/home.css b/youtube/static/home.css
new file mode 100644
index 0000000..9bea07c
--- /dev/null
+++ b/youtube/static/home.css
@@ -0,0 +1,197 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ border-radius: 5px;
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ margin: 0 auto;
+ max-width: 80ch;
+}
+
+.code-error {
+ background: var(--secondary-background);
+ padding: 1rem;
+}
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 780px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+ position: absolute;
+ }
+}
diff --git a/youtube/static/light_theme.css b/youtube/static/light_theme.css
index e4d7eb3..a0540f4 100644
--- a/youtube/static/light_theme.css
+++ b/youtube/static/light_theme.css
@@ -1,19 +1,17 @@
-body{
- --interface-color: #ffffff;
- --text-color: #222222;
- --background-color: #f8f8f8;
- --video-background-color: #ffffff;
+:root {
+ --background: #FAFAFA;
+ --text: #415462;
+ --secondary-hover: #415462;
+ --secondary-focus: rgba(115, 130, 140, 0.125);
+ --secondary-inverse: #FFF;
+ --secondary-background: #eeeeee;
+ --link: #22aaff;
+ --link-visited: #7755ff;
+ --buttom: #dcdcdb;
+ --buttom-text: #415462;
+ --button-border: #91918c;
+ --buttom-hover: #BBB;
+ --search-text: #415462;
+ --time-background: #000;
+ --time-text: #FFF;
}
-
-.comment .permalink{
- color: #000000;
-}
-
-.setting-item{
- background-color: #f8f8f8;
-}
-
-.muted{
- background-color: #888888;
-}
-
diff --git a/youtube/static/local_playlist.css b/youtube/static/local_playlist.css
new file mode 100644
index 0000000..bd68c5b
--- /dev/null
+++ b/youtube/static/local_playlist.css
@@ -0,0 +1,527 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.playlist-metadata {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+ grid-template-areas:
+ "play-title"
+ "play-action";
+}
+.play-title {
+ grid-area: play-title;
+ text-align: center;
+}
+.play-action {
+ grid-area: play-action;
+}
+
+/* Video list item */
+.video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.playlist-item .thumbnail-info {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ height: 100%;
+ width: 50%;
+ text-align: center;
+ white-space: pre-line;
+ opacity: .8;
+ color: var(--text);
+ font-size: 0.8125rem;
+ background: var(--secondary-background);
+ padding: 0;
+}
+
+.playlist-item .thumbnail-info span {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ text-transform: none;
+}
+
+.thumbnail-img {
+ margin: auto;
+ display: block;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.info-box {
+ grid-area: info-box;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto auto auto auto;
+ grid-gap: 1px;
+ grid-template-areas:
+ "."
+ "."
+ "."
+ "."
+ ".";
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+.horizontal-stats {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.horizontal-stats > li {
+ display: inline;
+}
+
+.horizontal-stats > li:first-child::after {
+ content: " | ";
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ .playlist-metadata {
+ max-width: 50vw;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/normalize.css b/youtube/static/normalize.css
new file mode 100644
index 0000000..192eb9c
--- /dev/null
+++ b/youtube/static/normalize.css
@@ -0,0 +1,349 @@
+/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
+
+/* Document
+ ========================================================================== */
+
+/**
+ * 1. Correct the line height in all browsers.
+ * 2. Prevent adjustments of font size after orientation changes in iOS.
+ */
+
+html {
+ line-height: 1.15; /* 1 */
+ -webkit-text-size-adjust: 100%; /* 2 */
+}
+
+/* Sections
+ ========================================================================== */
+
+/**
+ * Remove the margin in all browsers.
+ */
+
+body {
+ margin: 0;
+}
+
+/**
+ * Render the `main` element consistently in IE.
+ */
+
+main {
+ display: block;
+}
+
+/**
+ * Correct the font size and margin on `h1` elements within `section` and
+ * `article` contexts in Chrome, Firefox, and Safari.
+ */
+
+h1 {
+ font-size: 2em;
+ margin: 0.67em 0;
+}
+
+/* Grouping content
+ ========================================================================== */
+
+/**
+ * 1. Add the correct box sizing in Firefox.
+ * 2. Show the overflow in Edge and IE.
+ */
+
+hr {
+ box-sizing: content-box; /* 1 */
+ height: 0; /* 1 */
+ overflow: visible; /* 2 */
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+pre {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/* Text-level semantics
+ ========================================================================== */
+
+/**
+ * Remove the gray background on active links in IE 10.
+ */
+
+a {
+ background-color: transparent;
+}
+
+/**
+ * 1. Remove the bottom border in Chrome 57-
+ * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
+ */
+
+abbr[title] {
+ border-bottom: none; /* 1 */
+ text-decoration: underline; /* 2 */
+ text-decoration: underline dotted; /* 2 */
+}
+
+/**
+ * Add the correct font weight in Chrome, Edge, and Safari.
+ */
+
+b,
+strong {
+ font-weight: bolder;
+}
+
+/**
+ * 1. Correct the inheritance and scaling of font size in all browsers.
+ * 2. Correct the odd `em` font sizing in all browsers.
+ */
+
+code,
+kbd,
+samp {
+ font-family: monospace, monospace; /* 1 */
+ font-size: 1em; /* 2 */
+}
+
+/**
+ * Add the correct font size in all browsers.
+ */
+
+small {
+ font-size: 80%;
+}
+
+/**
+ * Prevent `sub` and `sup` elements from affecting the line height in
+ * all browsers.
+ */
+
+sub,
+sup {
+ font-size: 75%;
+ line-height: 0;
+ position: relative;
+ vertical-align: baseline;
+}
+
+sub {
+ bottom: -0.25em;
+}
+
+sup {
+ top: -0.5em;
+}
+
+/* Embedded content
+ ========================================================================== */
+
+/**
+ * Remove the border on images inside links in IE 10.
+ */
+
+img {
+ border-style: none;
+}
+
+/* Forms
+ ========================================================================== */
+
+/**
+ * 1. Change the font styles in all browsers.
+ * 2. Remove the margin in Firefox and Safari.
+ */
+
+button,
+input,
+optgroup,
+select,
+textarea {
+ font-family: inherit; /* 1 */
+ font-size: 100%; /* 1 */
+ line-height: 1.15; /* 1 */
+ margin: 0; /* 2 */
+}
+
+/**
+ * Show the overflow in IE.
+ * 1. Show the overflow in Edge.
+ */
+
+button,
+input { /* 1 */
+ overflow: visible;
+}
+
+/**
+ * Remove the inheritance of text transform in Edge, Firefox, and IE.
+ * 1. Remove the inheritance of text transform in Firefox.
+ */
+
+button,
+select { /* 1 */
+ text-transform: none;
+}
+
+/**
+ * Correct the inability to style clickable types in iOS and Safari.
+ */
+
+button,
+[type="button"],
+[type="reset"],
+[type="submit"] {
+ -webkit-appearance: button;
+}
+
+/**
+ * Remove the inner border and padding in Firefox.
+ */
+
+button::-moz-focus-inner,
+[type="button"]::-moz-focus-inner,
+[type="reset"]::-moz-focus-inner,
+[type="submit"]::-moz-focus-inner {
+ border-style: none;
+ padding: 0;
+}
+
+/**
+ * Restore the focus styles unset by the previous rule.
+ */
+
+button:-moz-focusring,
+[type="button"]:-moz-focusring,
+[type="reset"]:-moz-focusring,
+[type="submit"]:-moz-focusring {
+ outline: 1px dotted ButtonText;
+}
+
+/**
+ * Correct the padding in Firefox.
+ */
+
+fieldset {
+ padding: 0.35em 0.75em 0.625em;
+}
+
+/**
+ * 1. Correct the text wrapping in Edge and IE.
+ * 2. Correct the color inheritance from `fieldset` elements in IE.
+ * 3. Remove the padding so developers are not caught out when they zero out
+ * `fieldset` elements in all browsers.
+ */
+
+legend {
+ box-sizing: border-box; /* 1 */
+ color: inherit; /* 2 */
+ display: table; /* 1 */
+ max-width: 100%; /* 1 */
+ padding: 0; /* 3 */
+ white-space: normal; /* 1 */
+}
+
+/**
+ * Add the correct vertical alignment in Chrome, Firefox, and Opera.
+ */
+
+progress {
+ vertical-align: baseline;
+}
+
+/**
+ * Remove the default vertical scrollbar in IE 10+.
+ */
+
+textarea {
+ overflow: auto;
+}
+
+/**
+ * 1. Add the correct box sizing in IE 10.
+ * 2. Remove the padding in IE 10.
+ */
+
+[type="checkbox"],
+[type="radio"] {
+ box-sizing: border-box; /* 1 */
+ padding: 0; /* 2 */
+}
+
+/**
+ * Correct the cursor style of increment and decrement buttons in Chrome.
+ */
+
+[type="number"]::-webkit-inner-spin-button,
+[type="number"]::-webkit-outer-spin-button {
+ height: auto;
+}
+
+/**
+ * 1. Correct the odd appearance in Chrome and Safari.
+ * 2. Correct the outline style in Safari.
+ */
+
+[type="search"] {
+ -webkit-appearance: textfield; /* 1 */
+ outline-offset: -2px; /* 2 */
+}
+
+/**
+ * Remove the inner padding in Chrome and Safari on macOS.
+ */
+
+[type="search"]::-webkit-search-decoration {
+ -webkit-appearance: none;
+}
+
+/**
+ * 1. Correct the inability to style clickable types in iOS and Safari.
+ * 2. Change font properties to `inherit` in Safari.
+ */
+
+::-webkit-file-upload-button {
+ -webkit-appearance: button; /* 1 */
+ font: inherit; /* 2 */
+}
+
+/* Interactive
+ ========================================================================== */
+
+/*
+ * Add the correct display in Edge, IE 10+, and Firefox.
+ */
+
+details {
+ display: block;
+}
+
+/*
+ * Add the correct display in all browsers.
+ */
+
+summary {
+ display: list-item;
+}
+
+/* Misc
+ ========================================================================== */
+
+/**
+ * Add the correct display in IE 10+.
+ */
+
+template {
+ display: none;
+}
+
+/**
+ * Add the correct display in IE 10.
+ */
+
+[hidden] {
+ display: none;
+}
diff --git a/youtube/static/playlist.css b/youtube/static/playlist.css
new file mode 100644
index 0000000..8b75a7d
--- /dev/null
+++ b/youtube/static/playlist.css
@@ -0,0 +1,537 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.playlist-metadata {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+ grid-template-areas:
+ "author"
+ "summary"
+ "playlist-stats";
+}
+.author {
+ grid-area: author;
+ display: grid;
+ grid-template-columns: 100px 1fr;
+ grid-column-gap: 1rem;
+ align-items: center;
+ justify-self: center;
+}
+.summary {
+ grid-area: summary;
+ justify-self: start;
+}
+.playlist-stats {
+ grid-area: playlist-stats;
+ justify-self: start;
+}
+
+/* Video list item */
+.video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.playlist-item .thumbnail-info {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ height: 100%;
+ width: 50%;
+ text-align: center;
+ white-space: pre-line;
+ opacity: .8;
+ color: var(--text);
+ font-size: 0.8125rem;
+ background: var(--secondary-background);
+ padding: 0;
+}
+
+.playlist-item .thumbnail-info span {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ text-transform: none;
+}
+
+.thumbnail-img {
+ margin: auto;
+ display: block;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.info-box {
+ grid-area: info-box;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto auto auto auto;
+ grid-gap: 1px;
+ grid-template-areas:
+ "."
+ "."
+ "."
+ "."
+ ".";
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+.horizontal-stats {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.horizontal-stats > li {
+ display: inline;
+}
+
+.horizontal-stats > li:first-child::after {
+ content: " | ";
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ .playlist-metadata {
+ max-width: 50vw;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/search.css b/youtube/static/search.css
new file mode 100644
index 0000000..6c463bc
--- /dev/null
+++ b/youtube/static/search.css
@@ -0,0 +1,495 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.result-info {
+ justify-self: center;
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* Video list item */
+.video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.item-video.channel-item .thumbnail.channel {
+ padding: 0px;
+ text-align: center;
+}
+
+.item-video.channel-item .thumbnail-img.channel {
+ width: 56.25%;
+ position: relative;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.playlist-item .thumbnail-info {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ height: 100%;
+ width: 50%;
+ text-align: center;
+ white-space: pre-line;
+ opacity: .8;
+ color: var(--text);
+ font-size: 0.8125rem;
+ background: var(--secondary-background);
+ padding: 0;
+}
+
+.playlist-item .thumbnail-info span {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ text-transform: none;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+.horizontal-stats > li {
+ display: inline;
+}
+
+
+.horizontal-stats > li:first-child::after {
+ content: " | ";
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/settings.css b/youtube/static/settings.css
new file mode 100644
index 0000000..2e72505
--- /dev/null
+++ b/youtube/static/settings.css
@@ -0,0 +1,241 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ border-radius: 5px;
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ margin: 0 auto;
+ width: 100%;
+}
+
+.settings-form {
+ background-color: var(--secondary-background);
+ padding: 1rem;
+}
+
+.settings-list {
+ display: grid;
+ grid-row-gap: 1rem;
+ list-style: none;
+ padding: 0px;
+}
+
+.setting-item {
+ display: grid;
+ grid-template-columns: auto auto;
+ background-color: var(--secondary-focus);
+ align-items: center;
+ padding: 5px;
+}
+
+.setting-item select {
+ max-width: 100%;
+ justify-self: end;
+}
+
+.setting-item input {
+ max-width: 80px;
+ justify-self: end;
+}
+
+.settings-form input[type="submit"] {
+ cursor: pointer;
+}
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 780px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+ position: absolute;
+ background: var(--background);
+ padding-right: 4rem;
+ }
+ .main {
+ display: grid;
+ justify-content: center;
+ }
+ .settings-form {
+ width: 50vw;
+ }
+ .setting-item select {
+ max-width: 250px;
+ }
+ .setting-item input {
+ max-width: 250px;
+ }
+}
diff --git a/youtube/static/subscription.css b/youtube/static/subscription.css
new file mode 100644
index 0000000..74571fc
--- /dev/null
+++ b/youtube/static/subscription.css
@@ -0,0 +1,530 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.sidebar-links {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+ grid-template-areas:
+ "sidebar-title"
+ "sidebar-action";
+ align-items: center;
+ justify-items: center;
+ justify-content: center;
+}
+.sidebar-title {
+ grid-area: sidebar-title;
+ text-align: center;
+}
+.sidebar-action {
+ grid-area: sidebar-action;
+}
+
+/* Video list item */
+.video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.playlist-item .thumbnail-info {
+ position: absolute;
+ right: 0px;
+ bottom: 0px;
+ height: 100%;
+ width: 50%;
+ text-align: center;
+ white-space: pre-line;
+ opacity: .8;
+ color: var(--text);
+ font-size: 0.8125rem;
+ background: var(--secondary-background);
+ padding: 0;
+}
+
+.playlist-item .thumbnail-info span {
+ position: absolute;
+ top: 50%;
+ transform: translate(-50%, -50%);
+ text-transform: none;
+}
+
+.thumbnail-img {
+ margin: auto;
+ display: block;
+ max-height: 100%;
+ max-width: 100%;
+}
+
+.info-box {
+ grid-area: info-box;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto auto auto auto;
+ grid-gap: 1px;
+ grid-template-areas:
+ "."
+ "."
+ "."
+ "."
+ ".";
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+.horizontal-stats {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.horizontal-stats > li {
+ display: inline;
+}
+
+.horizontal-stats > li:first-child::after {
+ content: " | ";
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ .sidebar-links {
+ max-width: 50vw;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/subscription_manager.css b/youtube/static/subscription_manager.css
new file mode 100644
index 0000000..a7d9780
--- /dev/null
+++ b/youtube/static/subscription_manager.css
@@ -0,0 +1,403 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* playlist */
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+/* /playlist */
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+/* fix hr when is children of grid */
+hr {
+ width: 100%;
+}
+
+.import-export {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+ grid-template-areas:
+ "subscriptions-import-form";
+ align-items: center;
+ justify-items: center;
+ justify-content: center;
+}
+.subscriptions-import-form {
+ grid-area: subscriptions-import-form;
+ text-align: center;
+}
+
+.sub-list-controls {
+ display: grid;
+ grid-row-gap: 0.2rem;
+}
+
+.subscriptions-import-form input[type='submit'],
+.sub-list-controls button[type='submit'],
+.sub-list-controls input[type='reset'] {
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+
+.tag-group-list {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+}
+
+.sub-list {
+ display: grid;
+ grid-template-columns: 1fr;
+ margin: auto;
+}
+
+/* pagination */
+.main .pagination-container {
+ display: grid;
+ justify-content: center;
+}
+
+.main .pagination-container .pagination-list {
+ display: grid;
+ grid-auto-flow: column;
+ grid-column-gap: 0.5rem;
+}
+
+.main .pagination-container .pagination-list .page-link {
+ border-style: none;
+ font-weight: bold;
+ text-align: center;
+ background: var(--secondary-focus);
+ text-decoration: none;
+ align-self: center;
+ padding: .5rem;
+ width: 1rem;
+}
+
+.main .pagination-container .pagination-list .page-link.is-current {
+ background: var(--secondary-background);
+}
+
+/* /video list item */
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .info-box {
+ grid-gap: 2px;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 600px) {
+ .video-container {
+ display: grid;
+ grid-row-gap: 0.5rem;
+ grid-template-columns: 1fr 1fr;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ "main main main main"
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 100px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ background: var(--background);
+ padding-right: 4rem;
+ z-index: 1;
+ position: absolute;
+ }
+
+ .import-export {
+ max-width: 50vw;
+ }
+
+ .sub-list-controls {
+ grid-template-columns: repeat(8, auto);
+ max-height: 1rem;
+ grid-column-gap: 0.5rem;
+ justify-content: center;
+ align-items: center;
+ }
+
+ /* playlist */
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 100px);
+ }
+ .play-clean > button {
+ padding-left: 0px;
+ padding-right: 0px;
+ padding-bottom: 6px;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .video-container {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ grid-row-gap: 1rem;
+ grid-column-gap: 1rem;
+ }
+}
diff --git a/youtube/static/watch.css b/youtube/static/watch.css
new file mode 100644
index 0000000..697961d
--- /dev/null
+++ b/youtube/static/watch.css
@@ -0,0 +1,633 @@
+html {
+ font-family: "liberation serif", "times new roman", calibri, carlito, serif;
+ background: var(--background);
+ color: var(--text);
+}
+
+body {
+ display: grid;
+ grid-gap: 20px;
+ grid-template-areas:
+ "header"
+ "main"
+ "footer";
+ /* Fix height */
+ height: 100vh;
+ grid-template-rows: auto 1fr auto;
+ /* fix top and bottom */
+ margin-left: 1rem;
+ margin-right: 1rem;
+}
+
+img {
+ width: 100%;
+ height: auto;
+}
+
+video {
+ width: 100%;
+ height: auto;
+ max-height: 480px;
+}
+
+a:link {
+ color: var(--link);
+}
+
+a:visited {
+ color: var(--link-visited);
+}
+
+input[type="text"],
+input[type="search"] {
+ background: var(--background);
+ border: 1px solid var(--button-border);
+ border-radius: 5px;
+ padding: 0.4rem 0.4rem;
+ font-size: 15px;
+ color: var(--search-text);
+}
+
+input[type='search'] {
+ border-bottom: 1px solid var(--button-border);
+ border-top: 0px;
+ border-left: 0px;
+ border-right: 0px;
+ border-radius: 0px;
+}
+
+header {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "home"
+ "form"
+ "playlist";
+ grid-area: header;
+}
+
+.home {
+ grid-area: home;
+ margin-left: auto;
+ margin-right: auto;
+ margin-bottom: 1rem;
+ margin-top: 1rem;
+}
+
+.form {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "search-box"
+ "search-button"
+ "dropdown";
+ grid-area: form;
+}
+
+.search-box {
+ grid-area: search-box;
+}
+.search-button {
+ grid-area: search-button;
+
+ cursor: pointer;
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.search-button:hover {
+ background-color: var(--buttom-hover);
+}
+
+.dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+ z-index: 1;
+}
+.dropdown-label {
+ grid-area: dropdown-label;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.dropdown-label:hover {
+ background-color: var(--buttom-hover);
+}
+
+.playlist {
+ display: grid;
+ grid-gap: 4px;
+ grid-template-areas:
+ "play-box"
+ "play-hidden"
+ "play-add"
+ "play-clean";
+ grid-area: playlist;
+}
+.play-box {
+ grid-area: play-box;
+}
+
+.play-hidden {
+ grid-area: play-hidden;
+}
+
+.play-add {
+ grid-area: play-add;
+ cursor: pointer;
+
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-add:hover {
+ background-color: var(--buttom-hover);
+}
+
+.play-clean {
+ display: grid;
+ grid-area: play-clean;
+}
+
+.play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ border: 1px solid var(--button-border);
+ color: var(--buttom-text);
+ border-radius: 5px;
+}
+.play-clean > button:hover {
+ background-color: var(--buttom-hover);
+}
+
+/* ------------- Menu Mobile sin JS ---------------- */
+/* input hidden */
+.opt-box {
+ display: none;
+}
+.dropdown-content {
+ display: none;
+ grid-area: dropdown-content;
+}
+label[for=options-toggle-cbox] {
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+#options-toggle-cbox:checked ~ .dropdown-content {
+ display: inline-grid;
+ white-space: nowrap;
+ padding-left: 1rem;
+}
+/*- ----------- End Menu Mobile sin JS ------------- */
+
+.main {
+ grid-area: main;
+ margin: 0 auto;
+
+ display: grid;
+ grid-grap: 1px;
+ grid-template-columns: 1fr;
+ grid-template-areas:
+ "sc-video"
+ "sc-info";
+}
+.sc-video { grid-area: sc-video; }
+.sc-info {
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "video-info"
+ "side-videos"
+ "comments-area-outer";
+ grid-area: sc-info;
+}
+.video-info {
+ grid-area: video-info;
+
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ grid-template-areas:
+ "v-title v-title"
+ "v-uploaded v-views"
+ "v-published v-likes-dislikes"
+ "external-player-controls v-checkbox"
+ "v-download v-download"
+ "v-description v-description"
+ "v-music-list v-music-list"
+ "v-more-info v-more-info";
+}
+.v-title {
+ grid-area: v-title;
+ margin: 0px;
+}
+.v-uploaded { grid-area: v-uploaded; }
+.v-views {
+ grid-area: v-views;
+ justify-self: end;
+}
+.v-published { grid-area: v-published; }
+.v-likes-dislikes {
+ grid-area: v-likes-dislikes;
+ justify-self: end;
+}
+.external-player-controls {
+ grid-area: external-player-controls;
+}
+.external-player-controls input.speed {
+ width: 65px;
+ text-align: center;
+}
+.v-checkbox {
+ grid-area: v-checkbox;
+ justify-self: end;
+}
+.v-download { grid-area: v-download; }
+.v-download > ul.download-dropdown-content {
+ background: var(--secondary-background);
+ padding-left: 0px;
+}
+.v-download > ul.download-dropdown-content > li.download-format {
+ list-style: none;
+ padding: 0.4rem 0;
+ padding-left: 1rem;
+}
+.v-download > ul.download-dropdown-content > li.download-format a.download-link {
+ text-decoration: none;
+}
+
+.v-description {
+ grid-area: v-description;
+ background-color: var(--secondary-background);
+ margin-top: 0.4rem;
+ white-space: pre-wrap;
+ word-wrap: break-word;
+ padding: 5px;
+}
+
+.v-music-list {
+ grid-area: v-music-list;
+ padding-bottom: 1rem;
+}
+.v-music-list table,th,td{
+ border: 1px solid;
+}
+.v-music-list th,td{
+ padding-left:4px;
+ padding-right:5px;
+}
+.v-music-list caption{
+ text-align:left;
+ font-weight:bold;
+ margin-bottom:5px;
+}
+
+.v-more-info {
+ grid-area: v-more-info;
+}
+.v-more-info > .more-info-content {
+ background-color: var(--secondary-background);
+ padding: 5px;
+}
+
+.side-videos { grid-area: side-videos; }
+
+/* playlist items */
+.side-videos .site-playlist {
+ border-style: solid;
+ border-width: 2px;
+ border-color: var(--secondary-focus);
+ margin-bottom: 1rem;
+}
+
+.side-videos .site-playlist .playlist-header {
+ background-color: var(--secondary-background);
+ padding: 1rem;
+ border-bottom-style: solid;
+ border-bottom-width: 2px;
+ border-bottom-color: var(--secondary-focus);
+}
+
+.side-videos .site-playlist .playlist-header h3 {
+ margin: 0px;
+ padding: 0px;
+}
+
+.side-videos .site-playlist .playlist-header .playlist-metadata {
+ list-style: none;
+ display: grid;
+ justify-content: start;
+ padding: 0;
+ margin: 0px;
+ grid-template-columns: repeat(3, auto);
+ grid-column-gap: 1rem;
+}
+
+.side-videos .site-playlist .playlist-videos {
+ display: grid;
+ grid-row-gap: 1rem;
+ height: 300px;
+ overflow-y: scroll;
+ padding-top: 1rem;
+}
+
+.side-videos .site-playlist .playlist-videos article.item-box {
+ padding-left: 1rem;
+}
+/* /playlist items */
+
+.comments-area-outer { grid-area: comments-area-outer; }
+
+.related-videos-inner {
+ padding-top: 10px;
+ display: grid;
+ grid-row-gap: 1rem;
+}
+
+.item-box {
+ display: grid;
+ grid-template-columns: 1.9fr 0.1fr;
+ grid-template-rows: 1fr;
+ grid-gap: 1px;
+ grid-template-areas:
+ "item-video item-checkbox";
+}
+
+.item-video {
+ grid-area: item-video;
+
+ display: grid;
+ grid-template-columns: auto;
+ grid-template-rows: repeat(4, auto);
+ grid-row-gap: 0.4rem;
+ grid-template-areas:
+ "thumbnail-box"
+ "info-box";
+ align-items: center;
+
+ font-size: 0.7rem;
+}
+
+.item-video a {
+ text-decoration: none;
+ cursor: pointer;
+}
+
+.thumbnail-box {
+ grid-area: thumbnail-box;
+ position: relative;
+}
+
+.thumbnail {
+ padding: 28.125%;
+ position: relative;
+ box-sizing: border-box;
+}
+
+.thumbnail-img {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+ object-fit: cover;
+}
+
+.length {
+ z-index: 100;
+ position: absolute;
+ background-color: rgba(35, 35, 35, 0.75);
+ color: #fff;
+ border-radius: 2px;
+ padding: 2px;
+ font-size: 16px;
+ right: 0.25em;
+ bottom: -0.75em;
+}
+
+.info-box {
+ grid-area: info-box;
+ display: grid;
+ grid-template-columns: 1fr;
+ grid-template-rows: auto auto auto auto auto;
+ grid-gap: 1px;
+ grid-template-areas:
+ "."
+ "."
+ "."
+ "."
+ ".";
+}
+
+.title {
+ font-size: 0.8rem;
+ margin: 0px;
+ font-weight: normal;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.info-box address {
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.thumbnail-info {
+ background-color: var(--time-background);
+ color: #fff;
+ padding: 2px 5px;
+ text-transform: uppercase;
+ font-weight: 700;
+ font-size: 12px;
+ position: absolute;
+ right: 0;
+ bottom: .2rem;
+}
+
+.item-checkbox {
+ grid-area: item-checkbox;
+ justify-self: start;
+ align-self: center;
+ min-width: 30px;
+ margin: 0px;
+}
+
+.stats {
+ display: flex;
+ justify-content: space-between;
+}
+
+/* comments */
+.comments-area {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.comments {
+ display: grid;
+ grid-row-gap: 0.5rem;
+}
+
+.comment {
+ display: grid;
+ grid-template-columns: repeat(3, auto) 3fr;
+ grid-template-rows: repeat(4, auto);
+ grid-column-gap: 0.4rem;
+ grid-template-areas:
+ "author-avatar author-name permalink permalink"
+ "author-avatar comment-text comment-text comment-text"
+ ". comment-likes comment-likes comment-likes"
+ ". button-row button-row button-row";
+ background: var(--secondary-background);
+}
+
+.author-avatar { grid-area: author-avatar; }
+.author-name { grid-area: author-name; }
+.permalink { grid-area: permalink; }
+.comment-text { grid-area: comment-text; }
+.comment-likes { grid-area: comment-likes; }
+.button-row { grid-area: button-row; }
+
+.more-comments {
+ justify-self: center;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ background: var(--secondary-background);
+ padding: 5px;
+
+ /* disable text selection */
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.footer {
+ grid-area: footer;
+}
+
+.footer > p {
+ text-align: center;
+}
+
+@media (min-width: 480px) {
+ .item-video {
+ font-size: 0.85rem;
+ }
+ .title {
+ font-size: 1rem;
+ }
+}
+
+@media (min-width: 992px) {
+ body {
+ display: grid;
+ grid-template-columns: 0.3fr 2fr 1fr 0.3fr;
+ grid-template-rows: auto 1fr auto;
+ grid-template-areas:
+ "header header header header"
+ ". main main ."
+ "footer footer footer footer";
+ }
+ .form {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". search-box search-button dropdown";
+ grid-area: form;
+ position: relative;
+ }
+ .dropdown {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: minmax(50px, 120px);
+ grid-template-areas:
+ "dropdown-label"
+ "dropdown-content";
+ grid-area: dropdown;
+
+ background: var(--background);
+ padding-right: 4rem;
+
+ z-index: 1;
+ position: absolute;
+ }
+ .playlist {
+ display: grid;
+ grid-gap: 1px;
+ grid-template-columns: 1fr 1.4fr 0.3fr 1.3fr;
+ grid-template-areas: ". play-box play-add play-clean";
+ grid-area: playlist;
+ }
+ .play-clean {
+ grid-template-columns: minmax(50px, 120px);
+ }
+ .play-clean > button {
+ padding-bottom: 6px;
+ padding-left: .75em;
+ padding-right: .75em;
+ padding-top: 6px;
+ text-align: center;
+ white-space: nowrap;
+ background-color: var(--buttom);
+ color: var(--buttom-text);
+ border-radius: 5px;
+ cursor: pointer;
+ }
+
+ .main {
+ grid-area: main;
+ margin: 0px;
+ }
+
+ .sc-info {
+ display: grid;
+ grid-template-columns: 3fr 1fr;
+ grid-gap: 1px 40px;
+ grid-template-areas:
+ "video-info side-videos"
+ "comments-area-outer side-videos"
+ ". side-videos";
+ grid-area: sc-info;
+ }
+}
diff --git a/youtube/templates/base.html b/youtube/templates/base.html
index 3d9f1e9..4d03c05 100644
--- a/youtube/templates/base.html
+++ b/youtube/templates/base.html
@@ -1,203 +1,238 @@
<!DOCTYPE html>
<html>
<head>
- <meta charset="utf-8">
+ <meta charset="UTF-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1"/>
+ <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; media-src 'self' https://*.googlevideo.com; {{ "img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com;" if not settings.proxy_images else "" }}">
<title>{{ page_title }}</title>
- <meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline'; media-src 'self' https://*.googlevideo.com;
- {{ "img-src 'self' https://*.googleusercontent.com https://*.ggpht.com https://*.ytimg.com;" if not settings.proxy_images else "" }}">
- <link href="{{ theme_path }}" type="text/css" rel="stylesheet">
- <link href="/youtube.com/shared.css" type="text/css" rel="stylesheet">
- <link href="/youtube.com/static/comments.css" type="text/css" rel="stylesheet">
- <link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon">
- <link title="Youtube local" href="/youtube.com/opensearch.xml" rel="search" type="application/opensearchdescription+xml">
- <style type="text/css">
-{% block style %}
-{{ style }}
-{% endblock %}
- </style>
+ <link title="Youtube local" href="/youtube.com/opensearch.xml" rel="search" type="application/opensearchdescription+xml"/>
+ <link href="/youtube.com/static/favicon.ico" type="image/x-icon" rel="icon"/>
+ <link href="/youtube.com/static/normalize.css" rel="stylesheet"/>
+ <link href="{{ theme_path }}" rel="stylesheet"/>
+ {% block style %}
+ {{ style }}
+ {% endblock %}
</head>
- <body>
- <header>
- <a href="/youtube.com" id="home-link">Home</a>
- <form id="site-search" action="/youtube.com/search">
- <input type="search" name="query" class="search-box" value="{{ search_box_value }}"
- {{ "autofocus" if request.path == "/" else "" }}>
- <button type="submit" value="Search" class="search-button">Search</button>
- <div class="dropdown">
- <button class="dropdown-label">Options</button>
- <div class="css-sucks">
- <div class="dropdown-content">
- <h3>Sort by</h3>
- <input type="radio" id="sort_relevance" name="sort" value="0">
- <label for="sort_relevance">Relevance</label>
-
- <input type="radio" id="sort_upload_date" name="sort" value="2">
- <label for="sort_upload_date">Upload date</label>
-
- <input type="radio" id="sort_view_count" name="sort" value="3">
- <label for="sort_view_count">View count</label>
-
- <input type="radio" id="sort_rating" name="sort" value="1">
- <label for="sort_rating">Rating</label>
-
-
- <h3>Upload date</h3>
- <input type="radio" id="time_any" name="time" value="0">
- <label for="time_any">Any</label>
-
- <input type="radio" id="time_last_hour" name="time" value="1">
- <label for="time_last_hour">Last hour</label>
-
- <input type="radio" id="time_today" name="time" value="2">
- <label for="time_today">Today</label>
-
- <input type="radio" id="time_this_week" name="time" value="3">
- <label for="time_this_week">This week</label>
-
- <input type="radio" id="time_this_month" name="time" value="4">
- <label for="time_this_month">This month</label>
-
- <input type="radio" id="time_this_year" name="time" value="5">
- <label for="time_this_year">This year</label>
- <h3>Type</h3>
- <input type="radio" id="type_any" name="type" value="0">
- <label for="type_any">Any</label>
-
- <input type="radio" id="type_video" name="type" value="1">
- <label for="type_video">Video</label>
-
- <input type="radio" id="type_channel" name="type" value="2">
- <label for="type_channel">Channel</label>
-
- <input type="radio" id="type_playlist" name="type" value="3">
- <label for="type_playlist">Playlist</label>
-
- <input type="radio" id="type_movie" name="type" value="4">
- <label for="type_movie">Movie</label>
-
- <input type="radio" id="type_show" name="type" value="5">
- <label for="type_show">Show</label>
-
-
- <h3>Duration</h3>
- <input type="radio" id="duration_any" name="duration" value="0">
- <label for="duration_any">Any</label>
+ <body>
+ <header class="header">
+ <nav class="home">
+ <a href="/youtube.com" id="home-link">YouTube Local</a>
+ </nav>
+ <form class="form" id="site-search" action="/youtube.com/search">
+ <input type="search" name="query" class="search-box" value="{{ search_box_value }}"
+ {{ "autofocus" if request.path == "/" else "" }} placeholder="Type to search...">
+ <button type="submit" value="Search" class="search-button">Search</button>
+ <!-- options -->
+ <div class="dropdown">
+ <!-- hidden box -->
+ <input id="options-toggle-cbox" class="opt-box" role="button" type="checkbox">
+ <!-- end hidden box -->
+ <label class="dropdown-label" for="options-toggle-cbox">Options</label>
+ <div class="dropdown-content">
+ <h3>Sort by</h3>
+ <div class="option">
+ <input type="radio" id="sort_relevance" name="sort" value="0">
+ <label for="sort_relevance">Relevance</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="sort_upload_date" name="sort" value="2">
+ <label for="sort_upload_date">Upload date</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="sort_view_count" name="sort" value="3">
+ <label for="sort_view_count">View count</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="sort_rating" name="sort" value="1">
+ <label for="sort_rating">Rating</label>
+ </div>
- <input type="radio" id="duration_short" name="duration" value="1">
- <label for="duration_short">Short (&lt; 4 minutes)</label>
+ <h3>Upload date</h3>
+ <div class="option">
+ <input type="radio" id="time_any" name="time" value="0">
+ <label for="time_any">Any</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="time_last_hour" name="time" value="1">
+ <label for="time_last_hour">Last hour</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="time_today" name="time" value="2">
+ <label for="time_today">Today</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="time_this_week" name="time" value="3">
+ <label for="time_this_week">This week</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="time_this_month" name="time" value="4">
+ <label for="time_this_month">This month</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="time_this_year" name="time" value="5">
+ <label for="time_this_year">This year</label>
+ </div>
- <input type="radio" id="duration_long" name="duration" value="2">
- <label for="duration_long">Long (&gt; 20 minutes)</label>
+ <h3>Type</h3>
+ <div class="option">
+ <input type="radio" id="type_any" name="type" value="0">
+ <label for="type_any">Any</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="type_video" name="type" value="1">
+ <label for="type_video">Video</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="type_channel" name="type" value="2">
+ <label for="type_channel">Channel</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="type_playlist" name="type" value="3">
+ <label for="type_playlist">Playlist</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="type_movie" name="type" value="4">
+ <label for="type_movie">Movie</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="type_show" name="type" value="5">
+ <label for="type_show">Show</label>
+ </div>
- </div>
+ <h3>Duration</h3>
+ <div class="option">
+ <input type="radio" id="duration_any" name="duration" value="0">
+ <label for="duration_any">Any</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="duration_short" name="duration" value="1">
+ <label for="duration_short">Short (&lt; 4 minutes)</label>
+ </div>
+ <div class="option">
+ <input type="radio" id="duration_long" name="duration" value="2">
+ <label for="duration_long">Long (&gt; 20 minutes)</label>
</div>
</div>
- </form>
+ </div>
+ </form>
{% if header_playlist_names is defined %}
- <form id="playlist-edit" action="/youtube.com/edit_playlist" method="post" target="_self">
- <input name="playlist_name" id="playlist-name-selection" list="playlist-options" type="text">
- <datalist id="playlist-options">
- {% for playlist_name in header_playlist_names %}
- <option value="{{ playlist_name }}">{{ playlist_name }}</option>
- {% endfor %}
+ <form class="playlist" id="playlist-edit" action="/youtube.com/edit_playlist" method="post" target="_self">
+ <input class="play-box" name="playlist_name" id="playlist-name-selection" list="playlist-options" type="search" placeholder="I added your playlist...">
+ <datalist class="play-hidden" id="playlist-options">
+ {% for playlist_name in header_playlist_names %}
+ <option value="{{ playlist_name }}">{{ playlist_name }}</option>
+ {% endfor %}
</datalist>
- <button type="submit" id="playlist-add-button" name="action" value="add">Add to playlist</button>
- <button type="reset" id="item-selection-reset">Clear selection</button>
+ <button class="play-add" type="submit" id="playlist-add-button" name="action" value="add">+List</button>
+ <div class="play-clean">
+ <button type="reset" id="item-selection-reset">Clear selection</button>
+ </div>
</form>
+
<script>
- /* Takes control of the form if javascript is enabled, so that adding stuff to a playlist will not cause things to stop loading, and will display a status message. If javascript is disabled, the form will still work using regular HTML methods, but causes things on the page (such as the video) to stop loading. */
- var playlistAddForm = document.getElementById('playlist-edit');
-
- function setStyle(element, property, value){
- element.style[property] = value;
- }
- function removeMessage(messageBox){
- messageBox.parentNode.removeChild(messageBox);
- }
-
- function displayMessage(text, error=false){
- let currentMessageBox = document.getElementById('message-box');
- if(currentMessageBox !== null){
- currentMessageBox.parentNode.removeChild(currentMessageBox);
- }
- let messageBox = document.createElement('div');
- if(error){
- messageBox.setAttribute('role', 'alert');
- } else {
- messageBox.setAttribute('role', 'status');
- }
- messageBox.setAttribute('id', 'message-box');
- let textNode = document.createTextNode(text);
- messageBox.appendChild(textNode);
- document.querySelector('main').appendChild(messageBox);
- let currentstyle = window.getComputedStyle(messageBox);
- let removalDelay;
- if(error){
- removalDelay = 5000;
- } else {
- removalDelay = 1500;
- }
- window.setTimeout(setStyle, 20, messageBox, 'opacity', 1);
- window.setTimeout(setStyle, removalDelay, messageBox, 'opacity', 0);
- window.setTimeout(removeMessage, removalDelay+300, messageBox);
- }
- // https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
- function sendData(event){
- var clicked_button = document.activeElement;
- if(clicked_button === null || clicked_button.getAttribute('type') !== 'submit' || clicked_button.parentElement != event.target){
- console.log('ERROR: clicked_button not valid');
- return;
- }
- if(clicked_button.getAttribute('value') !== 'add'){
- return; // video(s) are being removed from playlist, just let it refresh the page
- }
- event.preventDefault();
- var XHR = new XMLHttpRequest();
- var FD = new FormData(playlistAddForm);
-
- if(FD.getAll('video_info_list').length === 0){
- displayMessage('Error: No videos selected', true);
- return;
- }
-
- if(FD.get('playlist_name') === ""){
- displayMessage('Error: No playlist selected', true);
- return;
- }
-
- // https://stackoverflow.com/questions/48322876/formdata-doesnt-include-value-of-buttons
- FD.append('action', 'add');
-
- XHR.addEventListener('load', function(event){
- if(event.target.status == 204){
- displayMessage('Added videos to playlist "' + FD.get('playlist_name') + '"');
- } else {
- displayMessage('Error adding videos to playlist: ' + event.target.status.toString(), true);
- }
- });
-
- XHR.addEventListener('error', function(event){
- if(event.target.status == 0){
- displayMessage('XHR failed: Check that XHR requests are allowed', true);
- } else {
- displayMessage('XHR failed: Unknown error', true);
- }
- });
-
- XHR.open('POST', playlistAddForm.getAttribute('action'));
- XHR.send(FD);
- }
-
- playlistAddForm.addEventListener('submit', sendData);
+ (function main() {
+ /* Takes control of the form if javascript is enabled, so that adding stuff to a playlist will not cause things to stop loading, and will display a status message. If javascript is disabled, the form will still work using regular HTML methods, but causes things on the page (such as the video) to stop loading. */
+ const playlistAddForm = document.getElementById('playlist-edit');
+
+ function setStyle(element, property, value){
+ element.style[property] = value;
+ }
+ function removeMessage(messageBox){
+ messageBox.parentNode.removeChild(messageBox);
+ }
+
+ function displayMessage(text, error=false){
+ let currentMessageBox = document.getElementById('message-box');
+ if(currentMessageBox !== null){
+ currentMessageBox.parentNode.removeChild(currentMessageBox);
+ }
+ let messageBox = document.createElement('div');
+ if(error){
+ messageBox.setAttribute('role', 'alert');
+ } else {
+ messageBox.setAttribute('role', 'status');
+ }
+ messageBox.setAttribute('id', 'message-box');
+ let textNode = document.createTextNode(text);
+ messageBox.appendChild(textNode);
+ document.querySelector('main').appendChild(messageBox);
+ let currentstyle = window.getComputedStyle(messageBox);
+ let removalDelay;
+ if(error){
+ removalDelay = 5000;
+ } else {
+ removalDelay = 1500;
+ }
+ window.setTimeout(setStyle, 20, messageBox, 'opacity', 1);
+ window.setTimeout(setStyle, removalDelay, messageBox, 'opacity', 0);
+ window.setTimeout(removeMessage, removalDelay+300, messageBox);
+ }
+ // https://developer.mozilla.org/en-US/docs/Learn/HTML/Forms/Sending_forms_through_JavaScript
+ function sendData(event){
+ var clicked_button = document.activeElement;
+ if(clicked_button === null || clicked_button.getAttribute('type') !== 'submit' || clicked_button.parentElement != event.target){
+ console.log('ERROR: clicked_button not valid');
+ return;
+ }
+ if(clicked_button.getAttribute('value') !== 'add'){
+ return; // video(s) are being removed from playlist, just let it refresh the page
+ }
+ event.preventDefault();
+ var XHR = new XMLHttpRequest();
+ var FD = new FormData(playlistAddForm);
+
+ if(FD.getAll('video_info_list').length === 0){
+ displayMessage('Error: No videos selected', true);
+ return;
+ }
+
+ if(FD.get('playlist_name') === ""){
+ displayMessage('Error: No playlist selected', true);
+ return;
+ }
+
+ // https://stackoverflow.com/questions/48322876/formdata-doesnt-include-value-of-buttons
+ FD.append('action', 'add');
+
+ XHR.addEventListener('load', function(event){
+ if(event.target.status == 204){
+ displayMessage('Added videos to playlist "' + FD.get('playlist_name') + '"');
+ } else {
+ displayMessage('Error adding videos to playlist: ' + event.target.status.toString(), true);
+ }
+ });
+
+ XHR.addEventListener('error', function(event){
+ if(event.target.status == 0){
+ displayMessage('XHR failed: Check that XHR requests are allowed', true);
+ } else {
+ displayMessage('XHR failed: Unknown error', true);
+ }
+ });
+
+ XHR.open('POST', playlistAddForm.getAttribute('action'));
+ XHR.send(FD);
+ }
+
+ playlistAddForm.addEventListener('submit', sendData);
+ }());
</script>
{% endif %}
+
</header>
- <main>
-{% block main %}
-{{ main }}
-{% endblock %}
+ <main class="main">
+
+ {% block main %}
+ {{ main }}
+ {% endblock %}
+
</main>
+ <footer class="footer">
+ <p>This site is Free/Libre Software</p>
+ <p>Current version: 3304bab @ master</p>
+ </footer>
</body>
+
</html>
diff --git a/youtube/templates/channel.html b/youtube/templates/channel.html
index dddbff1..25b0971 100644
--- a/youtube/templates/channel.html
+++ b/youtube/templates/channel.html
@@ -7,114 +7,30 @@
{% extends "base.html" %}
{% import "common_elements.html" as common_elements %}
{% block style %}
- main{
- display:grid;
-{% if current_tab == 'about' %}
- grid-template-rows: 0fr 0fr 1fr;
- grid-template-columns: 0fr 1fr;
-{% else %}
- grid-template-rows: repeat(5, 0fr);
- grid-template-columns: auto 1fr;
-{% endif %}
- }
- main .avatar{
- grid-row:1;
- grid-column:1;
- height:200px;
- width:200px;
- }
- main .summary{
- grid-row:1;
- grid-column:2;
- margin-left: 5px;
- }
- .summary subscribe-unsubscribe, .summary short-description{
- margin-top: 10px;
- }
- main .channel-tabs{
- grid-row:2;
- grid-column: 1 / span 2;
-
- display:grid;
- grid-auto-flow: column;
- justify-content:start;
-
- background-color: var(--interface-color);
- padding: 3px;
- padding-left: 6px;
- }
- #links-metadata{
- display: grid;
- grid-auto-flow: column;
- grid-column-gap: 10px;
- grid-column: 1/span 2;
- justify-content: start;
- padding-top: 8px;
- padding-bottom: 8px;
- padding-left: 6px;
- margin-bottom: 10px;
- }
- #number-of-results{
- font-weight:bold;
- }
- .content{
- grid-row: 4;
- grid-column: 1 / span 2;
- }
- .search-content{
- width: 800px;
- margin-left: 10px;
- }
- .item-grid{
- padding-left: 20px;
- }
- .item-list{
- width:800px;
- margin: auto;
- }
- .page-button-row{
- margin-left: auto;
- margin-right: auto;
- }
- .next-previous-button-row{
- margin-left: auto;
- margin-right: auto;
- }
- .tab{
- padding: 5px 75px;
- }
- .channel-info{
- grid-row: 3;
- grid-column: 1 / span 3;
- }
- .channel-info ul{
- padding-left: 40px;
- }
- .channel-info h3{
- margin-left: 40px;
- }
- .channel-info .description{
- white-space: pre-wrap;
- min-width: 0;
- margin-left: 40px;
- }
- .medium-item img{
- max-width: 168px;
- }
+ <link href="/youtube.com/static/channel.css" rel="stylesheet">
{% endblock style %}
{% block main %}
- <img class="avatar" src="{{ avatar }}">
- <div class="summary">
- <h2 class="title">{{ channel_name }}</h2>
- <p class="short-description">{{ short_description }}</p>
- <form method="POST" action="/youtube.com/subscriptions" class="subscribe-unsubscribe">
- <input type="submit" value="{{ 'Unsubscribe' if subscribed else 'Subscribe' }}">
- <input type="hidden" name="channel_id" value="{{ channel_id }}">
- <input type="hidden" name="channel_name" value="{{ channel_name }}">
- <input type="hidden" name="action" value="{{ 'unsubscribe' if subscribed else 'subscribe' }}">
- </form>
+
+ <div class="author-container">
+ <div class="author">
+ <img alt="{{ channel_name }}" src="{{ avatar }}"/>
+ <h2>{{ channel_name }}</h2>
+ </div>
+ <div class="summary">
+ <p>{{ short_description }}</p>
+ </div>
+ <div class="subscribe">
+ <form method="POST" action="/youtube.com/subscriptions" class="subscribe-unsubscribe">
+ <input class="btn-subscribe" type="submit" value="{{ 'Unsubscribe' if subscribed else 'Subscribe' }}">
+ <input type="hidden" name="channel_id" value="{{ channel_id }}">
+ <input type="hidden" name="channel_name" value="{{ channel_name }}">
+ <input type="hidden" name="action" value="{{ 'unsubscribe' if subscribed else 'subscribe' }}">
+ </form>
+ </div>
</div>
+ <hr/>
+
<nav class="channel-tabs">
{% for tab_name in ('Videos', 'Playlists', 'About') %}
{% if tab_name.lower() == current_tab %}
@@ -153,8 +69,9 @@
</ul>
</div>
{% else %}
- <div class="content {{ current_tab + '-content'}}">
- <div id="links-metadata">
+
+ <!-- new-->
+ <div id="links-metadata">
{% if current_tab == 'videos' %}
{% set sorts = [('1', 'views'), ('2', 'oldest'), ('3', 'newest')] %}
<div id="number-of-results">{{ number_of_videos }} videos</div>
@@ -177,16 +94,18 @@
<a class="sort-button" href="{{ channel_url + '/' + current_tab + '?sort=' + sort_number }}">{{ 'Sort by ' + sort_name }}</a>
{% endif %}
{% endfor %}
- </div>
+ </div>
- <nav class="{{ 'item-list' if current_tab == 'search' else 'item-grid' }}">
+ <div class="video-container {{ current_tab + '-content'}}">
{% for item_info in items %}
{{ common_elements.item(item_info, include_author=false) }}
{% endfor %}
- </nav>
+ </div>
+ <hr/>
+ <footer class="pagination-container">
{% if current_tab == 'videos' %}
- <nav class="page-button-row">
+ <nav class="pagination-list">
{{ common_elements.page_buttons(number_of_pages, channel_url + '/' + current_tab, parameters_dictionary) }}
</nav>
{% elif current_tab == 'search' %}
@@ -194,6 +113,8 @@
{{ common_elements.next_previous_buttons(is_last_page, channel_url + '/' + current_tab, parameters_dictionary) }}
</nav>
{% endif %}
- </div>
+ </footer>
+ <!-- /new-->
{% endif %}
+
{% endblock main %}
diff --git a/youtube/templates/comments.html b/youtube/templates/comments.html
index ad5ab02..a128b44 100644
--- a/youtube/templates/comments.html
+++ b/youtube/templates/comments.html
@@ -5,23 +5,24 @@
<div class="comment">
<a class="author-avatar" href="{{ comment['author_url'] }}" title="{{ comment['author'] }}">
{% if include_avatar %}
- <img class="author-avatar-img" src="{{ comment['author_avatar'] }}">
+ <img class="author-avatar-img" alt="{{ comment['author'] }}" src="{{ comment['author_avatar'] }}">
{% endif %}
</a>
- <address>
+ <address class="author-name">
<a class="author" href="{{ comment['author_url'] }}" title="{{ comment['author'] }}">{{ comment['author'] }}</a>
</address>
<a class="permalink" href="{{ comment['permalink'] }}" title="permalink">
- <time datetime="">{{ comment['time_published'] }}</time>
+ <time datetime="2012-01-14T15:23:44+02:00">{{ comment['time_published'] }}</time>
</a>
+
{% if timestamp_links %}
- <span class="text">{{ common_elements.text_runs(comment['text'])|timestamps|safe }}</span>
+ <span class="comment-text">{{ common_elements.text_runs(comment['text'])|timestamps|safe }}</span>
{% else %}
- <span class="text">{{ common_elements.text_runs(comment['text']) }}</span>
+ <span class="comment-text">{{ common_elements.text_runs(comment['text']) }}</span>
{% endif %}
- <span class="likes">{{ comment['likes_text'] if comment['like_count'] else ''}}</span>
- <div class="bottom-row">
+ <span class="comment-likes">{{ comment['likes_text'] if comment['like_count'] else ''}}</span>
+ <div class="button-row">
{% if settings.use_comments_js and comment['reply_count'] %}
<details class="replies" src="{{ comment['replies_url'] }}">
<summary>{{ comment['view_replies_text'] }}</summary>
@@ -33,7 +34,6 @@
{% endif %}
</div>
</div>
-
</div>
{% endmacro %}
@@ -57,8 +57,5 @@
<a class="page-button more-comments" href="{{ comments_info['more_comments_url'] }}">More comments</a>
{% endif %}
{% endif %}
-{% endmacro %}
-
-
-
+{% endmacro %}
diff --git a/youtube/templates/comments_page.html b/youtube/templates/comments_page.html
index 2d914af..09230f5 100644
--- a/youtube/templates/comments_page.html
+++ b/youtube/templates/comments_page.html
@@ -3,16 +3,11 @@
{% if not slim %}
{% extends "base.html" %}
-
{% block style %}
- .comments-area{
- margin: auto;
- width:640px;
- }
+ <link href="/youtube.com/static/comments.css" rel="stylesheet">
{% endblock style %}
{% endif %}
-
{% block main %}
<section class="comments-area">
{% if not comments_info['is_replies'] %}
@@ -27,7 +22,6 @@
</section>
{% endif %}
-
{% if not comments_info['is_replies'] %}
<div class="comment-links">
{% for link_text, link_url in comments_info['comment_links'] %}
@@ -51,5 +45,3 @@
<script src="/youtube.com/static/js/comments.js"></script>
{% endif %}
{% endblock main %}
-
-
diff --git a/youtube/templates/common_elements.html b/youtube/templates/common_elements.html
index 0587ce3..fcd4125 100644
--- a/youtube/templates/common_elements.html
+++ b/youtube/templates/common_elements.html
@@ -15,60 +15,55 @@
{% endmacro %}
{% macro item(info, description=false, horizontal=true, include_author=true, include_badges=true, lazy_load=false) %}
- <div class="item-box {{ info['type'] + '-item-box' }} {{'horizontal-item-box' if horizontal else 'vertical-item-box'}} {{'has-description' if description else 'no-description'}}">
+ <article class="item-box">
{% if info['error'] %}
{{ info['error'] }}
{% else %}
- <div class="item {{ info['type'] + '-item' }}">
+ <div class="item-video {{ info['type'] + '-item' }}">
<a class="thumbnail-box" href="{{ info['url'] }}" title="{{ info['title'] }}">
- {% if lazy_load %}
- <img class="thumbnail-img lazy" data-src="{{ info['thumbnail'] }}">
- {% else %}
- <img class="thumbnail-img" src="{{ info['thumbnail'] }}">
- {% endif %}
- {% if info['type'] != 'channel' %}
- <div class="thumbnail-info">
- <span>{{ (info['video_count']|commatize + ' videos') if info['type'] == 'playlist' else info['duration'] }}</span>
- </div>
- {% endif %}
- </a>
+ <div class="thumbnail {% if info['type'] == 'channel' %} channel {% endif %}">
+ {% if lazy_load %}
+ <img class="thumbnail-img lazy" alt="thumbnail" data-src="{{ info['thumbnail'] }}">
+ {% elif info['type'] == 'channel' %}
+ <img class="thumbnail-img channel" alt="thumbnail" src="{{ info['thumbnail'] }}">
+ {% else %}
+ <img class="thumbnail-img" alt="thumbnail" src="{{ info['thumbnail'] }}">
+ {% endif %}
- <div class="title"><a class="title" href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a></div>
+ {% if info['type'] != 'channel' %}
+ <p class="length">{{ (info['video_count']|commatize + ' videos') if info['type'] == 'playlist' else info['duration'] }}</p>
+ {% endif %}
+ </div>
+ </a>
+ <h4 class="title"><a href="{{ info['url'] }}" title="{{ info['title'] }}">{{ info['title'] }}</a></h4>
{% if include_author %}
{% if info.get('author_url') %}
- <address title="{{ info['author'] }}">By <a href="{{ info['author_url'] }}">{{ info['author'] }}</a></address>
+ <address title="{{ info['author'] }}"><b><a href="{{ info['author_url'] }}">{{ info['author'] }}</a></b></address>
{% else %}
<address title="{{ info['author'] }}"><b>{{ info['author'] }}</b></address>
{% endif %}
{% endif %}
- <ul class="stats {{'horizontal-stats' if horizontal else 'vertical-stats'}}">
+
+ <div class="stats {{'horizontal-stats' if horizontal else 'vertical-stats'}}">
{% if info['type'] == 'channel' %}
- <li><span>{{ info['approx_subscriber_count'] }} subscribers</span></li>
- <li><span>{{ info['video_count']|commatize }} videos</span></li>
+ <div>{{ info['approx_subscriber_count'] }} subscribers</div>
+ <div>{{ info['video_count']|commatize }} videos</div>
{% else %}
- {% if info.get('approx_view_count') %}
- <li><span class="views">{{ info['approx_view_count'] }} views</span></li>
- {% endif %}
{% if info.get('time_published') %}
- <li><time>{{ info['time_published'] }}</time></li>
+ <time>{{ info['time_published'] }}</time>
+ {% endif %}
+ {% if info.get('approx_view_count') %}
+ <div class="views">{{ info['approx_view_count'] }} views</div>
{% endif %}
{% endif %}
- </ul>
-
- {% if description %}
- <span class="description">{{ text_runs(info.get('description', '')) }}</span>
- {% endif %}
- {% if include_badges %}
- <span class="badges">{{ info['badges']|join(' | ') }}</span>
- {% endif %}
+ </div>
</div>
{% if info['type'] == 'video' %}
<input class="item-checkbox" type="checkbox" name="video_info_list" value="{{ info['video_info'] }}" form="playlist-edit">
{% endif %}
{% endif %}
- </div>
-
+ </article>
{% endmacro %}
{% macro page_buttons(estimated_pages, url, parameters_dictionary) %}
@@ -84,12 +79,12 @@
{% for page in range(page_start, page_end+1) %}
{% if page == current_page %}
- <div class="page-button">{{ page }}</div>
+ <div class="page-link is-current">{{ page }}</div>
{% else %}
{# IMPORTANT: Jinja SUCKS #}
{# https://stackoverflow.com/questions/36886650/how-to-add-a-new-entry-into-a-dictionary-object-while-using-jinja2 #}
{% set _ = parameters_dictionary.__setitem__('page', page) %}
- <a class="page-button" href="{{ url + '?' + parameters_dictionary|urlencode }}">{{ page }}</a>
+ <a class="page-link" href="{{ url + '?' + parameters_dictionary|urlencode }}">{{ page }}</a>
{% endif %}
{% endfor %}
@@ -101,11 +96,11 @@
{% if current_page != 1 %}
{% set _ = parameters_dictionary.__setitem__('page', current_page - 1) %}
- <a class="page-button previous-page" href="{{ url + '?' + parameters_dictionary|urlencode }}">Previous page</a>
+ <a class="page-link previous-page" href="{{ url + '?' + parameters_dictionary|urlencode }}">Previous page</a>
{% endif %}
{% if not is_last_page %}
{% set _ = parameters_dictionary.__setitem__('page', current_page + 1) %}
- <a class="page-button next-page" href="{{ url + '?' + parameters_dictionary|urlencode }}">Next page</a>
+ <a class="page-link next-page" href="{{ url + '?' + parameters_dictionary|urlencode }}">Next page</a>
{% endif %}
{% endmacro %}
diff --git a/youtube/templates/error.html b/youtube/templates/error.html
index c3f58b0..e02ecd9 100644
--- a/youtube/templates/error.html
+++ b/youtube/templates/error.html
@@ -4,9 +4,13 @@
{% extends "base.html" %}
{% endif %}
+{% block style %}
+ <link href="/youtube.com/static/home.css" rel="stylesheet">
+{% endblock style %}
+
{% block main %}
{% if traceback %}
- <div id="error-box">
+ <div class="code-error" id="error-box">
<h1>500 Uncaught exception:</h1>
<div class="code-box"><code>{{ traceback }}</code></div>
<p>Please report this issue at <a href="https://github.com/user234683/youtube-local/issues" target="_blank">https://github.com/user234683/youtube-local/issues</a></p>
@@ -16,4 +20,3 @@
<div id="error-message">{{ error_message }}</div>
{% endif %}
{% endblock %}
-
diff --git a/youtube/templates/home.html b/youtube/templates/home.html
index 9890f5e..0adac56 100644
--- a/youtube/templates/home.html
+++ b/youtube/templates/home.html
@@ -1,16 +1,7 @@
{% set page_title = title %}
{% extends "base.html" %}
{% block style %}
- ul {
- background-color: var(--interface-color);
- padding: 20px;
- width: 400px;
- margin: auto;
- margin-top: 20px;
- }
- li {
- margin-bottom: 10px;
- }
+ <link href="/youtube.com/static/home.css" rel="stylesheet">
{% endblock style %}
{% block main %}
<ul>
diff --git a/youtube/templates/local_playlist.html b/youtube/templates/local_playlist.html
index 803c4dc..bbe5edd 100644
--- a/youtube/templates/local_playlist.html
+++ b/youtube/templates/local_playlist.html
@@ -2,41 +2,23 @@
{% extends "base.html" %}
{% import "common_elements.html" as common_elements %}
{% block style %}
- main > *{
- width: 800px;
- margin: auto;
- }
-
- .playlist-metadata{
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- }
- .playlist-title{
- }
- #playlist-remove-button{
- align-self: center;
- white-space: nowrap;
- }
- #results{
- display: grid;
- grid-auto-rows: 0fr;
- grid-row-gap: 10px;
- }
+ <link href="/youtube.com/static/local_playlist.css" rel="stylesheet">
{% endblock style %}
{% block main %}
<div class="playlist-metadata">
- <h2 class="playlist-title">{{ playlist_name }}</h2>
+ <h2 class="play-title">{{ playlist_name }}</h2>
<input type="hidden" name="playlist_page" value="{{ playlist_name }}" form="playlist-edit">
- <button type="submit" id="playlist-remove-button" name="action" value="remove" form="playlist-edit" formaction="">Remove from playlist</button>
+ <button class="play-action" type="submit" id="playlist-remove-button" name="action" value="remove" form="playlist-edit" formaction="">Remove from playlist</button>
</div>
- <div id="results">
+ <div id="results" class="video-container">
{% for video_info in videos %}
{{ common_elements.item(video_info) }}
{% endfor %}
</div>
- <nav class="page-button-row">
- {{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlists/' + playlist_name, parameters_dictionary) }}
- </nav>
+ <footer class="pagination-container">
+ <nav class="pagination-list">
+ {{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlists/' + playlist_name, parameters_dictionary) }}
+ </nav>
+ </footer>
{% endblock main %}
diff --git a/youtube/templates/local_playlists_list.html b/youtube/templates/local_playlists_list.html
index a9fccff..f400808 100644
--- a/youtube/templates/local_playlists_list.html
+++ b/youtube/templates/local_playlists_list.html
@@ -2,20 +2,7 @@
{% extends "base.html" %}
{% block style %}
-main{
- display: flex;
- justify-content: center;
-}
- ul{
- background-color: var(--interface-color);
- margin-top: 20px;
- padding: 20px;
- min-width: 400px;
- align-self: start;
- }
- li{
- margin-bottom: 10px;
- }
+ <link href="/youtube.com/static/home.css" rel="stylesheet">
{% endblock style %}
{% block main %}
@@ -25,9 +12,3 @@ main{
{% endfor %}
</ul>
{% endblock main %}
-
-
-
-
-
-
diff --git a/youtube/templates/playlist.html b/youtube/templates/playlist.html
index af86c82..8c88cc7 100644
--- a/youtube/templates/playlist.html
+++ b/youtube/templates/playlist.html
@@ -2,77 +2,39 @@
{% extends "base.html" %}
{% import "common_elements.html" as common_elements %}
{% block style %}
- main > * {
- width: 800px;
- margin:auto;
- }
-
- .playlist-metadata{
- display:grid;
- grid-template-columns: 0fr 1fr;
- }
- .playlist-thumbnail{
- grid-row: 1 / span 5;
- grid-column:1;
- justify-self:start;
- width:250px;
- margin-right: 10px;
- }
- .playlist-title{
- grid-row: 1;
- grid-column:2;
- }
- .playlist-author{
- grid-row:2;
- grid-column:2;
- }
- .playlist-stats{
- grid-row:3;
- grid-column:2;
- }
-
- .playlist-description{
- grid-row:4;
- grid-column:2;
- min-width:0px;
- white-space: pre-line;
- }
-
- #results{
- margin-top:10px;
-
- display: grid;
- grid-auto-rows: 0fr;
- grid-row-gap: 10px;
-
- }
+ <link href="/youtube.com/static/playlist.css" rel="stylesheet">
{% endblock style %}
{% block main %}
+
<div class="playlist-metadata">
- <img class="playlist-thumbnail" src="{{ thumbnail }}">
- <h2 class="playlist-title">{{ title }}</h2>
- <a class="playlist-author" href="{{ author_url }}">{{ author }}</a>
+ <div class="author">
+ <img alt="{{ title }}" src="{{ thumbnail }}"/>
+ <h2>{{ title }}</h2>
+ </div>
+ <div class="summary">
+ <a class="playlist-author" href="{{ author_url }}">{{ author }}</a>
+ </div>
<div class="playlist-stats">
<div>{{ video_count|commatize }} videos</div>
<div>{{ view_count|commatize }} views</div>
<div>Last updated {{ time_published }}</div>
</div>
- <div class="playlist-description">{{ common_elements.text_runs(description) }}</div>
</div>
+ <hr/>
- <div id="results">
+
+ <div id="results" class="video-container">
{% for info in video_list %}
{{ common_elements.item(info) }}
{% endfor %}
</div>
- <nav class="page-button-row">
- {{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlist', parameters_dictionary) }}
- </nav>
-{% endblock main %}
-
-
-
-
+ <hr/>
+ <footer class="pagination-container">
+ <nav class="pagination-list">
+ {{ common_elements.page_buttons(num_pages, '/https://www.youtube.com/playlist', parameters_dictionary) }}
+ </nav>
+ </footer>
+{% endblock main %}
diff --git a/youtube/templates/search.html b/youtube/templates/search.html
index 8b803e7..e742099 100644
--- a/youtube/templates/search.html
+++ b/youtube/templates/search.html
@@ -3,44 +3,31 @@
{% extends "base.html" %}
{% import "common_elements.html" as common_elements %}
{% block style %}
- main > * {
- max-width: 800px;
- margin: auto;
- }
- #result-info{
- margin-top: 10px;
- margin-bottom: 10px;
- padding-left: 10px;
- padding-right: 10px;
- }
- #number-of-results{
- font-weight:bold;
- }
- .item-list{
- padding-left: 10px;
- padding-right: 10px;
- }
- .badge{
- background-color:#cccccc;
- }
+ <link href="/youtube.com/static/search.css" rel="stylesheet">
{% endblock style %}
{% block main %}
- <div id="result-info">
- <div id="number-of-results">Approximately {{ '{:,}'.format(estimated_results) }} results ({{ '{:,}'.format(estimated_pages) }} pages)</div>
-{% if corrections['type'] == 'showing_results_for' %}
- <div>Showing results for <a>{{ common_elements.text_runs(corrections['corrected_query_text']) }}</a></div>
- <div>Search instead for <a href="{{ corrections['original_query_url'] }}">{{ corrections['original_query_text'] }}</a></div>
-{% elif corrections['type'] == 'did_you_mean' %}
- <div>Did you mean <a href="{{ corrections['corrected_query_url'] }}">{{ common_elements.text_runs(corrections['corrected_query_text']) }}</a></div>
-{% endif %}
- </div>
- <div class="item-list">
- {% for info in results %}
- {{ common_elements.item(info, description=true) }}
- {% endfor %}
- </div>
- <nav class="page-button-row">
- {{ common_elements.page_buttons(estimated_pages, '/https://www.youtube.com/search', parameters_dictionary) }}
- </nav>
+ <div class="result-info" id="result-info">
+ <div id="number-of-results">Approximately {{ '{:,}'.format(estimated_results) }} results ({{ '{:,}'.format(estimated_pages) }} pages)</div>
+ {% if corrections['type'] == 'showing_results_for' %}
+ <div>Showing results for <a>{{ common_elements.text_runs(corrections['corrected_query_text']) }}</a></div>
+ <div>Search instead for <a href="{{ corrections['original_query_url'] }}">{{ corrections['original_query_text'] }}</a></div>
+ {% elif corrections['type'] == 'did_you_mean' %}
+ <div>Did you mean <a href="{{ corrections['corrected_query_url'] }}">{{ common_elements.text_runs(corrections['corrected_query_text']) }}</a></div>
+ {% endif %}
+ </div>
+
+ <!-- video item -->
+ <div class="video-container">
+ {% for info in results %}
+ {{ common_elements.item(info, description=true) }}
+ {% endfor %}
+ </div>
+ <hr/>
+ <!-- /video item -->
+ <footer class="pagination-container">
+ <nav class="pagination-list">
+ {{ common_elements.page_buttons(estimated_pages, '/https://www.youtube.com/search', parameters_dictionary) }}
+ </nav>
+ </footer>
{% endblock main %}
diff --git a/youtube/templates/settings.html b/youtube/templates/settings.html
index 19817dd..5385c68 100644
--- a/youtube/templates/settings.html
+++ b/youtube/templates/settings.html
@@ -1,28 +1,7 @@
{% set page_title = 'Settings' %}
{% extends "base.html" %}
-{% import "common_elements.html" as common_elements %}
{% block style %}
- .settings-form {
- margin: auto;
- width: 600px;
- margin-top:10px;
- padding: 10px;
- display: block;
- background-color: var(--interface-color);
- }
- .settings-list{
- list-style: none;
- padding: 0px;
- }
- .setting-item{
- margin-bottom: 10px;
- padding: 5px;
- }
- .setting-item label{
- display: inline-block;
- width: 250px;
- }
-
+ <link href="/youtube.com/static/settings.css" rel="stylesheet">
{% endblock style %}
{% block main %}
@@ -30,37 +9,37 @@
{% for categ in categories %}
<h2>{{ categ|capitalize }}</h2>
<ul class="settings-list">
- {% for setting_name, setting_info, value in settings_by_category[categ] %}
- {% if not setting_info.get('hidden', false) %}
- <li class="setting-item">
- {% if 'label' is in(setting_info) %}
- <label for="{{ 'setting_' + setting_name }}">{{ setting_info['label'] }}</label>
- {% else %}
- <label for="{{ 'setting_' + setting_name }}">{{ setting_name.replace('_', ' ')|capitalize }}</label>
- {% endif %}
-
- {% if setting_info['type'].__name__ == 'bool' %}
- <input type="checkbox" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" {{ 'checked' if value else '' }}>
- {% elif setting_info['type'].__name__ == 'int' %}
- {% if 'options' is in(setting_info) %}
- <select id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}">
- {% for option in setting_info['options'] %}
- <option value="{{ option[0] }}" {{ 'selected' if option[0] == value else '' }}>{{ option[1] }}</option>
- {% endfor %}
- </select>
+ {% for setting_name, setting_info, value in settings_by_category[categ] %}
+ {% if not setting_info.get('hidden', false) %}
+ <li class="setting-item">
+ {% if 'label' is in(setting_info) %}
+ <label for="{{ 'setting_' + setting_name }}">{{ setting_info['label'] }}</label>
{% else %}
- <input type="number" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}" step="1">
+ <label for="{{ 'setting_' + setting_name }}">{{ setting_name.replace('_', ' ')|capitalize }}</label>
{% endif %}
- {% elif setting_info['type'].__name__ == 'float' %}
- {% elif setting_info['type'].__name__ == 'str' %}
- <input type="text" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}">
- {% else %}
- <span>Error: Unknown setting type: setting_info['type'].__name__</span>
- {% endif %}
- </li>
- {% endif %}
- {% endfor %}
+ {% if setting_info['type'].__name__ == 'bool' %}
+ <input type="checkbox" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" {{ 'checked' if value else '' }}>
+ {% elif setting_info['type'].__name__ == 'int' %}
+ {% if 'options' is in(setting_info) %}
+ <select id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}">
+ {% for option in setting_info['options'] %}
+ <option value="{{ option[0] }}" {{ 'selected' if option[0] == value else '' }}>{{ option[1] }}</option>
+ {% endfor %}
+ </select>
+ {% else %}
+ <input type="number" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}" step="1">
+ {% endif %}
+ {% elif setting_info['type'].__name__ == 'float' %}
+
+ {% elif setting_info['type'].__name__ == 'str' %}
+ <input type="text" id="{{ 'setting_' + setting_name }}" name="{{ setting_name }}" value="{{ value }}">
+ {% else %}
+ <span>Error: Unknown setting type: setting_info['type'].__name__</span>
+ {% endif %}
+ </li>
+ {% endif %}
+ {% endfor %}
</ul>
{% endfor %}
<input type="submit" value="Save settings">
diff --git a/youtube/templates/subscription_manager.html b/youtube/templates/subscription_manager.html
index 4d798e0..3b8a5c0 100644
--- a/youtube/templates/subscription_manager.html
+++ b/youtube/templates/subscription_manager.html
@@ -1,81 +1,7 @@
{% set page_title = 'Subscription Manager' %}
{% extends "base.html" %}
{% block style %}
- .import-export{
- display: flex;
- flex-direction: row;
- padding-left: 10px;
- padding-top: 10px;
- }
- .subscriptions-import-form{
- background-color: var(--interface-color);
- display: flex;
- flex-direction: column;
- align-items: flex-start;
- max-width: 300px;
- padding:10px;
- }
- .subscriptions-import-form h2{
- font-size: 1.25rem;
- margin-bottom: 10px;
- }
-
- .import-submit-button{
- margin-top:15px;
- align-self: flex-end;
- }
-
-
- .subscriptions-export-links{
- margin: 0px 0px 0px 20px;
- background-color: var(--interface-color);
- list-style: none;
- max-width: 300px;
- padding:10px;
- }
-
- .sub-list-controls{
- background-color: var(--interface-color);
- padding:10px;
- }
-
-
- .tag-group-list{
- list-style: none;
- margin-left: 10px;
- margin-right: 10px;
- padding: 0px;
- }
- .tag-group{
- border-style: solid;
- margin-bottom: 10px;
- }
-
- .sub-list{
- list-style: none;
- padding:10px;
- column-width: 300px;
- column-gap: 40px;
- }
- .sub-list-item{
- display:flex;
- margin-bottom: 10px;
- break-inside:avoid;
- }
- .sub-list-item:not(.muted){
- background-color: var(--interface-color);
- }
- .tag-list{
- margin-left:15px;
- font-weight:bold;
- }
- .sub-list-item-name{
- margin-left:15px;
- }
- .sub-list-checkbox{
- height: 1.5em;
- min-width: 1.5em; // need min-width otherwise browser doesn't respect the width and squishes the checkbox down when there's too many tags
- }
+ <link href="/youtube.com/static/subscription_manager.css" rel="stylesheet">
{% endblock style %}
@@ -89,8 +15,6 @@
{% endfor %}
{% endmacro %}
-
-
{% block main %}
<div class="import-export">
<form class="subscriptions-import-form" enctype="multipart/form-data" action="/youtube.com/import_subscriptions" method="POST">
diff --git a/youtube/templates/subscriptions.html b/youtube/templates/subscriptions.html
index e2fb25c..9e48c6b 100644
--- a/youtube/templates/subscriptions.html
+++ b/youtube/templates/subscriptions.html
@@ -7,79 +7,21 @@
{% import "common_elements.html" as common_elements %}
{% block style %}
- main{
- display:flex;
- flex-direction: row;
- }
- .video-section{
- flex-grow: 1;
- padding-left: 10px;
- padding-top: 10px;
- }
- .current-tag{
- margin-bottom:10px;
- }
- .video-section .page-button-row{
- justify-content: center;
- }
- .subscriptions-sidebar{
- flex-basis: 300px;
- background-color: var(--interface-color);
- border-left: 2px;
- }
- .sidebar-links{
- display:flex;
- justify-content: space-between;
- padding-left:10px;
- padding-right: 10px;
- }
-
- .sidebar-list{
- list-style: none;
- padding-left:10px;
- padding-right: 10px;
- }
- .sidebar-list-item{
- display:flex;
- justify-content: space-between;
- margin-bottom: 5px;
- }
- .sub-refresh-list .sidebar-item-name{
- text-overflow: clip;
- white-space: nowrap;
- overflow: hidden;
- max-width: 200px;
- }
+ <link href="/youtube.com/static/subscription.css" rel="stylesheet">
{% endblock style %}
{% block main %}
- <div class="video-section">
- {% if current_tag %}
- <h2 class="current-tag">{{ current_tag }}</h2>
- {% endif %}
- <nav class="item-grid">
- {% for video_info in videos %}
- {{ common_elements.item(video_info) }}
- {% endfor %}
- </nav>
-
- <nav class="page-button-row">
- {{ common_elements.page_buttons(num_pages, '/youtube.com/subscriptions', parameters_dictionary) }}
- </nav>
- </div>
<div class="subscriptions-sidebar">
<div class="sidebar-links">
- <a href="/youtube.com/subscription_manager" class="sub-manager-link">Subscription Manager</a>
- <form method="POST" class="refresh-all">
+ <a class="sidebar-title" href="/youtube.com/subscription_manager" class="sub-manager-link">Subscription Manager</a>
+ <form class="sidebar-action" method="POST" class="refresh-all">
<input type="submit" value="Check All">
<input type="hidden" name="action" value="refresh">
<input type="hidden" name="type" value="all">
</form>
</div>
- <hr>
-
<ol class="sidebar-list tags">
{% if current_tag %}
<li class="sidebar-list-item">
@@ -105,7 +47,6 @@
</ol>
<hr>
-
<ol class="sidebar-list sub-refresh-list">
{% for subscription in subscription_list %}
<li class="sidebar-list-item {{ 'muted' if subscription['muted'] else '' }}">
@@ -119,7 +60,23 @@
</li>
{% endfor %}
</ol>
+ </div>
+
+ {% if current_tag %}
+ <h2 class="current-tag">{{ current_tag }}</h2>
+ {% endif %}
+ <div class="video-container">
+ {% for video_info in videos %}
+ {{ common_elements.item(video_info) }}
+ {% endfor %}
</div>
+ <hr/>
+
+ <footer class="pagination-container">
+ <nav class="pagination-list">
+ {{ common_elements.page_buttons(num_pages, '/youtube.com/subscriptions', parameters_dictionary) }}
+ </nav>
+ </footer>
{% endblock main %}
diff --git a/youtube/templates/watch.html b/youtube/templates/watch.html
index 36b2198..44fc5a7 100644
--- a/youtube/templates/watch.html
+++ b/youtube/templates/watch.html
@@ -3,378 +3,17 @@
{% import "common_elements.html" as common_elements %}
{% import "comments.html" as comments with context %}
{% block style %}
- details > summary{
- background-color: var(--interface-color);
- border-style: outset;
- border-width: 2px;
- font-weight: bold;
- padding-bottom: 2px;
- }
- details > summary:hover{
- text-decoration: underline;
- }
-
- .playability-error{
- height: 360px;
- width: 640px;
- grid-column: 2;
- background-color: var(--video-background-color);
- text-align:center;
- }
- .playability-error span{
- position: relative;
- top: 50%;
- transform: translate(-50%, -50%);
- }
-
- .live-url-choices{
- height: 360px;
- width: 640px;
- grid-column: 2;
- background-color: var(--video-background-color);
- padding: 25px 0px 0px 25px;
- }
- .live-url-choices ol{
- list-style: none;
- padding:0px;
- margin:0px;
- margin-top: 15px;
- }
- .live-url-choices input{
- width: 400px;
- }
- .url-choice-label{
- display: inline-block;
- width: 150px;
- }
-
- {% if settings.theater_mode %}
- /* This is the constant aspect ratio trick
- Percentages in padding-top declarations are based on the width of the
- parent element. We can use this trick to achieve a constant aspect ratio
- for video-container-inner by setting height to 0.
-
- So the video height will decrease if the browser window is narrow,
- but it will keep same aspect ratio. Must use absolute positioning on
- video to keep it inside its container since the container's height is 0.
-
- However, because we widen the video player longer than the video's
- intrinsic width for long video to make scrubbing easier, we can't use
- the aspect ratio to set the height. The height needs to be the
- intrinsic height in these cases. So we use a media query so aspect
- ratio trick is only used if page width is less than or equal to
- intrinsic video width.
- */
- #video-container{
- grid-column: 1 / span 5;
- justify-self: center;
- max-width: 100%;
- width: {{ theater_video_target_width }}px;
- margin-bottom: 10px;
- }
- #video-container-inner{
- height: {{ video_height}}px;
- position: relative;
- }
- @media(max-width:{{ video_width }}px){
- #video-container-inner{
- padding-top: calc(100%*{{video_height}}/{{video_width}});
- height: 0px;
- }
- }
- video{
- background-color: var(--video-background-color);
- position: absolute;
- top: 0px;
- left: 0px;
- width: 100%;
- height: 100%;
- }
- .side-videos{
- grid-row: 2 /span 3;
- width: 400px;
- }
- .video-info{
- width: 640px;
- }
- {% else %}
- #video-container{
- grid-column: 2;
- }
- #video-container, #video-container-inner, video{
- height: 360px;
- width: 640px;
- }
- .side-videos{
- grid-row: 1 /span 4;
- }
- {% endif %}
-
- main{
- display:grid;
- grid-template-columns: 1fr 640px 40px 400px 1fr;
- grid-template-rows: auto auto auto auto;
- align-content: start;
- }
-
- .video-info{
- grid-column: 2;
- grid-row: 2;
- display: grid;
- grid-template-rows: 0fr 0fr 0fr 20px 0fr 0fr;
- grid-template-columns: 1fr 1fr;
- align-content: start;
- }
- .video-info > .title{
- grid-column: 1 / span 2;
- min-width: 0;
- }
- .video-info > .labels{
- justify-self:start;
- list-style: none;
- padding: 0px;
- margin: 5px 0px;
- }
- .video-info > .labels:empty{
- margin: 0px;
- }
- .labels > li{
- display: inline;
- margin-right:5px;
- background-color: var(--interface-color);
- padding: 2px 5px;
- border-style: solid;
- border-width: 1px;
- }
- .video-info > address{
- grid-column: 1;
- grid-row: 3;
- justify-self: start;
- }
- .video-info > .views{
- grid-column: 2;
- grid-row: 3;
- justify-self:end;
- }
- .video-info > time{
- grid-column: 1;
- grid-row: 4;
- justify-self:start;
- }
- .video-info > .likes-dislikes{
- grid-column: 2;
- grid-row: 4;
- justify-self:end;
- }
- .video-info > .external-player-controls{
- justify-self: start;
- grid-row: 5;
- grid-column: 1;
- margin-bottom: 8px;
- }
- #speed-control{
- width: 65px;
- text-align: center;
- background-color: var(--interface-color);
- color: var(--text-color);
- }
- .video-info > .checkbox{
- justify-self:end;
- align-self: start;
-
- grid-row: 5;
- grid-column: 2;
- }
- .video-info > .download-dropdown{
- grid-column:1 / span 2;
- grid-row: 6;
- }
- .video-info > .description{
- background-color:var(--interface-color);
- margin-top:8px;
- white-space: pre-wrap;
- min-width: 0;
- word-wrap: break-word;
- grid-column: 1 / span 2;
- grid-row: 7;
- padding: 5px;
- }
-
- .music-list{
- grid-row:8;
- grid-column: 1 / span 2;
- background-color: var(--interface-color);
- padding-bottom: 7px;
- }
- .music-list table,th,td{
- border: 1px solid;
- }
- .music-list th,td{
- padding-left:4px;
- padding-right:5px;
- }
- .music-list caption{
- text-align:left;
- font-weight:bold;
- margin-bottom:5px;
- }
- .more-info{
- grid-row: 9;
- grid-column: 1 / span 2;
- background-color: var(--interface-color);
- }
- .more-info > summary{
- font-weight: normal;
- border-width: 1px 0px;
- border-style: solid;
- }
- .more-info-content{
- padding: 5px;
- }
- .more-info-content p{
- margin: 8px 0px;
- }
- .comments-area-outer{
- grid-column: 2;
- grid-row: 3;
- margin-top:10px;
- }
- .comments-disabled{
- background-color: var(--interface-color);
- padding: 5px;
- font-weight: bold;
- }
- .comments-area-inner{
- padding-top: 10px;
- }
- .comment{
- width:640px;
- }
-
- .side-videos{
- grid-column: 4;
- max-width: 640px;
- }
- #transcript-details{
- margin-bottom: 10px;
- }
- table#transcript-table {
- border-collapse: collapse;
- width: 100%;
- }
- table#transcript-table td, th {
- border: 1px solid #dddddd;
- }
- div#transcript-div {
- background-color: var(--interface-color);
- padding: 5px;
- }
- .playlist{
- border-style: solid;
- border-width: 2px;
- border-color: lightgray;
- margin-bottom: 10px;
- }
- .playlist-header{
- background-color: var(--interface-color);
- padding: 3px;
- border-bottom-style: solid;
- border-bottom-width: 2px;
- border-bottom-color: lightgray;
- }
- .playlist-header h3{
- margin: 2px;
- }
- .playlist-metadata{
- list-style: none;
- padding: 0px;
- margin: 0px;
- }
- .playlist-metadata li{
- display: inline;
- margin: 2px;
- }
- .playlist-videos{
- height: 300px;
- overflow-y: scroll;
- display: grid;
- grid-auto-rows: 90px;
- grid-row-gap: 10px;
- padding-top: 10px;
- }
- .related-videos-inner{
- padding-top: 10px;
- display: grid;
- grid-auto-rows: 90px;
- grid-row-gap: 10px;
- }
- .thumbnail-box{ /* overides rule in shared.css */
- height: 90px !important;
- width: 120px !important;
- }
-
- /* Put related vids below videos when window is too small */
- /* 1100px instead of 1080 because W3C is full of idiots who include scrollbar width */
- @media (max-width:1100px){
- main{
- grid-template-columns: 1fr 640px 40px 1fr;
- }
- .side-videos{
- margin-top: 10px;
- grid-column: 2;
- grid-row: 3;
- width: initial;
- }
- .comments-area-outer{
- grid-row: 4;
- }
- }
-
- .download-dropdown-content{
- background-color: var(--interface-color);
- padding: 10px;
- list-style: none;
- margin: 0px;
- }
- li.download-format{
- margin-bottom: 7px;
- }
- .format-attributes{
- list-style: none;
- padding: 0px;
- margin: 0px;
- display: flex;
- flex-direction: row;
- }
- .format-attributes li{
- white-space: nowrap;
- max-height: 1.2em;
- }
- .format-ext{
- width: 60px;
- }
- .format-video-quality{
- width: 140px;
- }
- .format-audio-quality{
- width: 120px;
- }
- .format-file-size{
- width: 80px;
- }
- .format-codecs{
- width: 120px;
- }
+ <link href="/youtube.com/static/watch.css" rel="stylesheet">
{% endblock style %}
{% block main %}
{% if playability_error %}
<div class="playability-error">
<span>{{ 'Error: ' + playability_error }}
- {% if invidious_reload_button %}
- <a href="{{ video_url }}&use_invidious=0"><br>
-Reload without invidious (for usage of new identity button).</a>
- {% endif %}
+ {% if invidious_reload_button %}
+ <a href="{{ video_url }}&use_invidious=0"><br>
+ Reload without invidious (for usage of new identity button).</a>
+ {% endif %}
</span>
</div>
{% elif (video_sources.__len__() == 0 or live) and hls_formats.__len__() != 0 %}
@@ -387,143 +26,137 @@ Reload without invidious (for usage of new identity button).</a>
</ol>
</div>
{% else %}
- <div id="video-container">
- <div id="video-container-inner">
- <video controls autofocus class="video" height="{{ video_height }}px">
- {% for video_source in video_sources %}
- <source src="{{ video_source['src'] }}" type="{{ video_source['type'] }}">
- {% endfor %}
+ <figure class="sc-video">
+ <video id="js-video-player" playsinline controls>
+ {% for video_source in video_sources %}
+ <source src="{{ video_source['src'] }}" type="{{ video_source['type'] }}">
+ {% endfor %}
- {% for source in subtitle_sources %}
- {% if source['on'] %}
- <track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
- {% else %}
- <track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
- {% endif %}
- {% endfor %}
+ {% for source in subtitle_sources %}
+ {% if source['on'] %}
+ <track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}" default>
+ {% else %}
+ <track label="{{ source['label'] }}" src="{{ source['url'] }}" kind="subtitles" srclang="{{ source['srclang'] }}">
+ {% endif %}
+ {% endfor %}
+ </video>
+ </figure>
- </video>
- </div>
- </div>
{% if time_start != 0 %}
<script>
- document.querySelector('video').currentTime = {{ time_start|tojson }};
+ document.querySelector('js-video-player').currentTime = {{ time_start|tojson }};
</script>
{% endif %}
{% endif %}
- <div class="video-info">
- <h2 class="title">{{ title }}</h2>
- <ul class="labels">
- {%- if unlisted -%}
- <li class="is-unlisted">Unlisted</li>
- {%- endif -%}
- {%- if age_restricted -%}
- <li class="age-restricted">Age-restricted</li>
- {%- endif -%}
- {%- if limited_state -%}
- <li>Limited state</li>
- {%- endif -%}
- {%- if live -%}
- <li>Live</li>
- {%- endif -%}
- </ul>
- <address>Uploaded by <a href="{{ uploader_channel_url }}">{{ uploader }}</a></address>
- <span class="views">{{ view_count }} views</span>
-
-
- <time datetime="$upload_date">Published on {{ time_published }}</time>
- <span class="likes-dislikes">{{ like_count }} likes {{ dislike_count }} dislikes</span>
-
- <div class="external-player-controls">
- <input id="speed-control" type="text">
- <script>
- var video = document.querySelector('video');
- var speedInput = document.querySelector('#speed-control');
- speedInput.addEventListener('keyup', (event) => {
- if (event.key === 'Enter') {
- var speed = parseFloat(speedInput.value);
- if(!isNaN(speed)){
- video.playbackRate = speed;
- }
- }
- });
- </script>
- </div>
- <input class="checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
-
- <details class="download-dropdown">
- <summary class="download-dropdown-label">Download</summary>
- <ul class="download-dropdown-content">
- {% for format in download_formats %}
- <li class="download-format">
- <a class="download-link" href="{{ format['url'] }}">
- <ol class="format-attributes">
- <li class="format-ext">{{ format['ext'] }}</li>
- <li class="format-video-quality">{{ format['video_quality'] }}</li>
- <li class="format-audio-quality">{{ format['audio_quality'] }}</li>
- <li class="format-file-size">{{ format['file_size'] }}</li>
- <li class="format-codecs">{{ format['codecs'] }}</li>
- </ol>
- </a>
- </li>
- {% endfor %}
- {% for download in other_downloads %}
- <li class="download-format">
- <a href="{{ download['url'] }}">
- <ol class="format-attributes">
- <li class="format-ext">{{ download['ext'] }}</li>
- <li class="format-label">{{ download['label'] }}</li>
- </ol>
- </a>
- </li>
- {% endfor %}
+ <div class="sc-info">
+ <div class="video-info">
+ <h1 class="v-title">{{ title }}</h1>
+
+ <ul class="labels">
+ {%- if unlisted -%}
+ <li class="is-unlisted">Unlisted</li>
+ {%- endif -%}
+ {%- if age_restricted -%}
+ <li class="age-restricted">Age-restricted</li>
+ {%- endif -%}
+ {%- if limited_state -%}
+ <li>Limited state</li>
+ {%- endif -%}
+ {%- if live -%}
+ <li>Live</li>
+ {%- endif -%}
</ul>
- </details>
+ <address class="v-uploaded">Uploaded by <a href="{{ uploader_channel_url }}">{{ uploader }}</a></address>
+ <span class="v-views">{{ view_count }} views</span>
+ <time class="v-published" datetime="$upload_date">Published on {{ time_published }}</time>
+ <span class="v-likes-dislikes">{{ like_count }} likes {{ dislike_count }} dislikes</span>
+
+ <div class="external-player-controls">
+ <input class="speed" id="speed-control" type="text">
+ <script>
+ (function main() {
+ 'use strict';
+ const video = document.getElementById('js-video-player');
+ const speedInput = document.getElementById('speed-control');
+ speedInput.addEventListener('keyup', (event) => {
+ if (event.key === 'Enter') {
+ let speed = parseFloat(speedInput.value);
+ if(!isNaN(speed)){
+ video.playbackRate = speed;
+ }
+ }
+ });
+ }());
+ </script>
+ </div>
- <span class="description">{{ common_elements.text_runs(description)|escape|urlize|timestamps|safe }}</span>
- <div class="music-list">
- {% if music_list.__len__() != 0 %}
- <hr>
- <table>
- <caption>Music</caption>
- <tr>
- {% for attribute in music_attributes %}
- <th>{{ attribute }}</th>
- {% endfor %}
- </tr>
- {% for track in music_list %}
+ <input class="v-checkbox" name="video_info_list" value="{{ video_info }}" form="playlist-edit" type="checkbox">
+
+ <details class="v-download">
+ <summary class="download-dropdown-label">Download</summary>
+ <ul class="download-dropdown-content">
+ {% for format in download_formats %}
+ <li class="download-format">
+ <a class="download-link" href="{{ format['url'] }}" download="{{ title }}.{{ format['ext'] }}">
+ {{ format['ext'] }} {{ format['video_quality'] }} {{ format['audio_quality'] }} {{ format['file_size'] }} {{ format['codecs'] }}
+ </a>
+ </li>
+ {% endfor %}
+ {% for download in other_downloads %}
+ <li class="download-format">
+ <a href="{{ download['url'] }}" download>
+ {{ download['ext'] }} {{ download['label'] }}
+ </a>
+ </li>
+ {% endfor %}
+ </ul>
+ </details>
+ <span class="v-description">{{ common_elements.text_runs(description)|escape|urlize|timestamps|safe }}</span>
+
+ <div class="v-music-list">
+ {% if music_list.__len__() != 0 %}
+ <hr>
+ <table>
+ <caption>Music</caption>
<tr>
{% for attribute in music_attributes %}
- <td>{{ track.get(attribute.lower(), '') }}</td>
+ <th>{{ attribute }}</th>
{% endfor %}
</tr>
- {% endfor %}
- </table>
- {% endif %}
- </div>
- <details class="more-info">
- <summary>More info</summary>
- <div class="more-info-content">
- <p>Tor exit node: {{ ip_address }}</p>
- {% if invidious_used %}
- <p>Used Invidious as fallback.</p>
- {% endif %}
- <p class="allowed-countries">Allowed countries: {{ allowed_countries|join(', ') }}</p>
-
- {% if settings.use_sponsorblock_js %}
- <ul class="more-actions">
- <li><label><input type=checkbox id=skip_sponsors checked>skip sponsors</label> <span id=skip_n></span>
- </ul>
+ {% for track in music_list %}
+ <tr>
+ {% for attribute in music_attributes %}
+ <td>{{ track.get(attribute.lower(), '') }}</td>
+ {% endfor %}
+ </tr>
+ {% endfor %}
+ </table>
{% endif %}
</div>
- </details>
- </div>
+ <details class="v-more-info">
+ <summary>More info</summary>
+ <div class="more-info-content">
+ <p>Tor exit node: {{ ip_address }}</p>
+ {% if invidious_used %}
+ <p>Used Invidious as fallback.</p>
+ {% endif %}
+ <p class="allowed-countries">Allowed countries: {{ allowed_countries|join(', ') }}</p>
+ {% if settings.use_sponsorblock_js %}
+ <ul class="more-actions">
+ <li><label><input type=checkbox id=skip_sponsors checked>skip sponsors</label> <span id=skip_n></span>
+ </ul>
+ {% endif %}
+ </div>
+ </details>
+ </div>
+
+ <div class="side-videos">
- <div class="side-videos">
- {% if playlist %}
- <div class="playlist">
+ <!-- playlist -->
+ {% if playlist %}
+ <div class="site-playlist">
<div class="playlist-header">
<a href="{{ playlist['url'] }}" title="{{ playlist['title'] }}"><h3>{{ playlist['title'] }}</h3></a>
<ul class="playlist-metadata">
@@ -550,167 +183,171 @@ Reload without invidious (for usage of new identity button).</a>
</nav>
{% if playlist['current_index'] is not none %}
<script>
- // from https://stackoverflow.com/a/6969486
- function escapeRegExp(string) {
- return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
- }
- var playability_error = {{ 'true' if playability_error else 'false' }};
- var playlist_id = {{ playlist['id']|tojson }};
- playlist_id = escapeRegExp(playlist_id);
-
- // read cookies on whether to autoplay thru playlist
- // pain in the ass:
- // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie
- var cookieValue = document.cookie.replace(new RegExp(
- '(?:(?:^|.*;\\s*)autoplay_' + playlist_id + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
- var autoplayEnabled = 0;
- if(cookieValue.length === 0){
- autoplayEnabled = 0;
- } else {
- autoplayEnabled = Number(cookieValue);
- }
-
- // check the checkbox if autoplay is on
- var checkbox = document.querySelector('#autoplay-toggle');
- if(autoplayEnabled){
- checkbox.checked = true;
- }
-
- // listen for checkbox to turn autoplay on and off
- checkbox.addEventListener( 'change', function() {
- if(this.checked) {
- autoplayEnabled = 1;
- document.cookie = 'autoplay_' + playlist_id + '=1';
- } else {
- autoplayEnabled = 0;
- document.cookie = 'autoplay_' + playlist_id + '=0';
- }
- });
-
- if(!playability_error){
- // play the video if autoplay is on
- var vid = document.querySelector('video');
- if(autoplayEnabled){
- vid.play();
- }
- }
-
- var currentIndex = {{ playlist['current_index']|tojson }};
- {% if playlist['current_index']+1 == playlist['items']|length %}
- var nextVideoUrl = null;
- {% else %}
- var nextVideoUrl = {{ (playlist['items'][playlist['current_index']+1]['url'])|tojson }};
- {% endif %}
- var nextVideoDelay = 1000;
-
- // scroll playlist to proper position
- var pl = document.querySelector('.playlist-videos');
- // item height + gap == 100
- pl.scrollTop = 100*currentIndex;
-
- // go to next video when video ends
- // https://stackoverflow.com/a/2880950
- if(nextVideoUrl){
- if(playability_error){
- videoEnded();
- } else {
- vid.addEventListener('ended', videoEnded, false);
- }
- function nextVideo(){
- if(autoplayEnabled){
- window.location.href = nextVideoUrl;
- }
- }
- function videoEnded(e) {
- window.setTimeout(nextVideo, nextVideoDelay);
- }
- }
+ (function main() {
+ // from https://stackoverflow.com/a/6969486
+ function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
+ }
+ let playability_error = {{ 'true' if playability_error else 'false' }};
+ let playlist_id = {{ playlist['id']|tojson }};
+ playlist_id = escapeRegExp(playlist_id);
+
+ // read cookies on whether to autoplay thru playlist
+ // pain in the ass:
+ // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie
+ let cookieValue = document.cookie.replace(new RegExp(
+ '(?:(?:^|.*;\\s*)autoplay_' + playlist_id + '\\s*\\=\\s*([^;]*).*$)|^.*$'), '$1');
+ let autoplayEnabled = 0;
+ if(cookieValue.length === 0){
+ autoplayEnabled = 0;
+ } else {
+ autoplayEnabled = Number(cookieValue);
+ }
+
+ // check the checkbox if autoplay is on
+ let checkbox = document.querySelector('#autoplay-toggle');
+ if(autoplayEnabled){
+ checkbox.checked = true;
+ }
+
+ // listen for checkbox to turn autoplay on and off
+ checkbox.addEventListener( 'change', function() {
+ if(this.checked) {
+ autoplayEnabled = 1;
+ document.cookie = 'autoplay_' + playlist_id + '=1';
+ } else {
+ autoplayEnabled = 0;
+ document.cookie = 'autoplay_' + playlist_id + '=0';
+ }
+ });
+
+ const vid = document.getElementById('js-video-player');
+ if(!playability_error){
+ if(autoplayEnabled){
+ vid.play();
+ }
+ }
+
+ let currentIndex = {{ playlist['current_index']|tojson }};
+ {% if playlist['current_index']+1 == playlist['items']|length %}
+ let nextVideoUrl = null;
+ {% else %}
+ let nextVideoUrl = {{ (playlist['items'][playlist['current_index']+1]['url'])|tojson }};
+ {% endif %}
+ let nextVideoDelay = 1000;
+
+ // scroll playlist to proper position
+ let pl = document.querySelector('.playlist-videos');
+ // item height + gap == 100
+ pl.scrollTop = 100*currentIndex;
+
+ // go to next video when video ends
+ // https://stackoverflow.com/a/2880950
+ if(nextVideoUrl){
+ if(playability_error){
+ videoEnded();
+ } else {
+ vid.addEventListener('ended', videoEnded, false);
+ }
+ function nextVideo(){
+ if(autoplayEnabled){
+ window.location.href = nextVideoUrl;
+ }
+ }
+ function videoEnded(e) {
+ window.setTimeout(nextVideo, nextVideoDelay);
+ }
+ }
+ }());
</script>
{% endif %}
{% if playlist['id'] is not none %}
<script>
- // lazy load playlist images
- // copied almost verbatim from
- // https://css-tricks.com/tips-for-rolling-your-own-lazy-loading/
- // IntersectionObserver isn't supported in pre-quantum
- // firefox versions, but the alternative of making it
- // manually is a performance drain, so oh well
- var observer = new IntersectionObserver(lazyLoad, {
-
- // where in relation to the edge of the viewport, we are observing
- rootMargin: "100px",
-
- // how much of the element needs to have intersected
- // in order to fire our loading function
- threshold: 1.0
-
- });
-
- function lazyLoad(elements) {
- elements.forEach(item => {
- if (item.intersectionRatio > 0) {
-
- // set the src attribute to trigger a load
- item.target.src = item.target.dataset.src;
-
- // stop observing this element. Our work here is done!
- observer.unobserve(item.target);
- };
- });
- };
-
- // Tell our observer to observe all img elements with a "lazy" class
- var lazyImages = document.querySelectorAll('img.lazy');
- lazyImages.forEach(img => {
- observer.observe(img);
- });
+ (function main() {
+ // lazy load playlist images
+ // copied almost verbatim from
+ // https://css-tricks.com/tips-for-rolling-your-own-lazy-loading/
+ // IntersectionObserver isn't supported in pre-quantum
+ // firefox versions, but the alternative of making it
+ // manually is a performance drain, so oh well
+ let observer = new IntersectionObserver(lazyLoad, {
+ // where in relation to the edge of the viewport, we are observing
+ rootMargin: "100px",
+ // how much of the element needs to have intersected
+ // in order to fire our loading function
+ threshold: 1.0
+ });
+
+ function lazyLoad(elements) {
+ elements.forEach(item => {
+ if (item.intersectionRatio > 0) {
+ // set the src attribute to trigger a load
+ item.target.src = item.target.dataset.src;
+ // stop observing this element. Our work here is done!
+ observer.unobserve(item.target);
+ };
+ });
+ };
+
+ // Tell our observer to observe all img elements with a "lazy" class
+ let lazyImages = document.querySelectorAll('img.lazy');
+ lazyImages.forEach(img => {
+ observer.observe(img);
+ });
+ }());
</script>
{% endif %}
</div>
- {% endif %}
+ {% endif %}
+ <!-- /playlist -->
+
+ {% if subtitle_sources %}
+ <details id="transcript-details">
+ <summary>Transcript</summary>
+ <div id="transcript-div">
+ <select id="select-tt">
+ {% for source in subtitle_sources %}
+ <option>{{ source['label'] }}</option>
+ {% endfor %}
+ </select>
+ <label for="transcript-use-table">Table view</label>
+ <input id="transcript-use-table" type="checkbox">
+ <table id="transcript-table"></table>
+ </div>
+ </details>
+ {% endif %}
+
- {% if subtitle_sources %}
- <details id="transcript-details">
- <summary>Transcript</summary>
- <div id="transcript-div">
- <select id="select-tt">
- {% for source in subtitle_sources %}
- <option>{{ source['label'] }}</option>
+ {% if settings.related_videos_mode != 0 %}
+ <details class="related-videos-outer" {{'open' if settings.related_videos_mode == 1 else ''}}>
+ <summary>Related Videos</summary>
+ <nav class="related-videos-inner">
+ {% for info in related %}
+ {{ common_elements.item(info, include_badges=false) }}
{% endfor %}
- </select>
- <label for="transcript-use-table">Table view</label>
- <input type="checkbox" id="transcript-use-table">
- <table id="transcript-table"></table>
- </div>
- </details>
- {% endif %}
+ </nav>
+ </details>
+ {% endif %}
- {% if settings.related_videos_mode != 0 %}
- <details class="related-videos-outer" {{'open' if settings.related_videos_mode == 1 else ''}}>
- <summary>Related Videos</summary>
- <nav class="related-videos-inner">
- {% for info in related %}
- {{ common_elements.item(info, include_badges=false) }}
- {% endfor %}
- </nav>
- </details>
- {% endif %}
- </div>
+ </div>
- {% if settings.comments_mode != 0 %}
- {% if comments_disabled %}
- <div class="comments-area-outer comments-disabled">Comments disabled</div>
- {% else %}
- <details class="comments-area-outer" {{'open' if settings.comments_mode == 1 else ''}}>
- <summary>{{ comment_count|commatize }} comment{{'s' if comment_count != 1 else ''}}</summary>
- <section class="comments-area-inner comments-area">
- {% if comments_info %}
- {{ comments.video_comments(comments_info) }}
- {% endif %}
- </section>
- </details>
+ <!-- comments -->
+ {% if settings.comments_mode != 0 %}
+ {% if comments_disabled %}
+ <div class="comments-area-outer comments-disabled">Comments disabled</div>
+ {% else %}
+ <details class="comments-area-outer" {{'open' if settings.comments_mode == 1 else ''}}>
+ <summary>{{ comment_count|commatize }} comment{{'s' if comment_count != 1 else ''}}</summary>
+ <div class="comments-area-inner comments-area">
+ {% if comments_info %}
+ {{ comments.video_comments(comments_info) }}
+ {% endif %}
+ </div>
+ </details>
+ {% endif %}
{% endif %}
- {% endif %}
+
+ </div>
<script> data = {{ js_data|tojson }} </script>
<script src="/youtube.com/static/js/common.js"></script>