diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index b34cfcf..335da9a 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,13 +1,13 @@ -# These are supported funding model platforms - -github: CodeYourFuture -patreon: # Replace with a single Patreon username -open_collective: # Replace with a single Open Collective username -ko_fi: # Replace with a single Ko-fi username -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry -custom: https://codeyourfuture.io/donate +# These are supported funding model platforms + +github: CodeYourFuture +patreon: # Replace with a single Patreon username +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry +custom: https://codeyourfuture.io/donate diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 5fe8ffd..3e43fc2 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,14 +1,14 @@ -blank_issues_enabled: false -contact_links: - - name: CYF - url: contact@codeyourfuture.io - about: Please report serious issues here. - - name: Join CYF - url: https://codeyourfuture.io/volunteers/ - about: Join CYF here - - name: CYF Slack - url: codeyourfuture.slack.com - about: Come to #cyf-syllabus-tech and chat - - name: CYF Tech Ed - url: https://github.com/orgs/CodeYourFuture/teams/mentors - about: CYF mentors on Github +blank_issues_enabled: false +contact_links: + - name: CYF + url: contact@codeyourfuture.io + about: Please report serious issues here. + - name: Join CYF + url: https://codeyourfuture.io/volunteers/ + about: Join CYF here + - name: CYF Slack + url: codeyourfuture.slack.com + about: Come to #cyf-syllabus-tech and chat + - name: CYF Tech Ed + url: https://github.com/orgs/CodeYourFuture/teams/mentors + about: CYF mentors on Github diff --git a/.github/ISSUE_TEMPLATE/pd-assignment.yml b/.github/ISSUE_TEMPLATE/pd-assignment.yml index c8bd229..3c739f7 100644 --- a/.github/ISSUE_TEMPLATE/pd-assignment.yml +++ b/.github/ISSUE_TEMPLATE/pd-assignment.yml @@ -1,59 +1,59 @@ -name: PD Coursework -description: Assign a piece of PD coursework -title: "[PD] " -labels: [PD, 🏝 Priority Stretch, 🐇 Size Small] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to assign this coursework! - - type: input - attributes: - label: Coursework content - validations: - required: true - - type: input - attributes: - label: Estimated time in hours - description: (PD has max 4 per week total) - validations: - required: true - - type: textarea - attributes: - label: What is the purpose of this assignment? - description: Clearly explain the purpose of this assignment and how trainees can evaluate this. - validations: - required: true - - type: textarea - attributes: - label: How to submit - description: State in clear steps how a trainee can submit this assignment. - placeholder: | - Copy the Google doc to your own Google Drive - Complete the work assigned - When you are ready, move your document to your class Drive - validations: - required: true - - type: textarea - attributes: - label: Anything else? - description: | - Links? References? Anything that will give more context - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - - type: markdown - attributes: - value: | - **Thank you so much.** - - Please now complete this ticket by filling in the options on the sidebar. - - 1. Update labels - - priority -- is this coursework key, mandatory, or stretch? - - size -- help trainees plan their time with rough estimation - 2. Add to project backlog - - add to the project named the same as this repo - - fill in custom fields -- priority, size, hours, week -- to match this issue - - Once your ticket is complete, you may like to check it out on the example project board attached to this repo. - This is so you understand how trainees will use your work. +name: PD Coursework +description: Assign a piece of PD coursework +title: "[PD] <title>" +labels: [PD, 🏝 Priority Stretch, 🐇 Size Small] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to assign this coursework! + - type: input + attributes: + label: Coursework content + validations: + required: true + - type: input + attributes: + label: Estimated time in hours + description: (PD has max 4 per week total) + validations: + required: true + - type: textarea + attributes: + label: What is the purpose of this assignment? + description: Clearly explain the purpose of this assignment and how trainees can evaluate this. + validations: + required: true + - type: textarea + attributes: + label: How to submit + description: State in clear steps how a trainee can submit this assignment. + placeholder: | + Copy the Google doc to your own Google Drive + Complete the work assigned + When you are ready, move your document to your class Drive + validations: + required: true + - type: textarea + attributes: + label: Anything else? + description: | + Links? References? Anything that will give more context + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + - type: markdown + attributes: + value: | + **Thank you so much.** + + Please now complete this ticket by filling in the options on the sidebar. + + 1. Update labels + - priority -- is this coursework key, mandatory, or stretch? + - size -- help trainees plan their time with rough estimation + 2. Add to project backlog + - add to the project named the same as this repo + - fill in custom fields -- priority, size, hours, week -- to match this issue + + Once your ticket is complete, you may like to check it out on the example project board attached to this repo. + This is so you understand how trainees will use your work. diff --git a/.github/ISSUE_TEMPLATE/tech-ed-assignment.yml b/.github/ISSUE_TEMPLATE/tech-ed-assignment.yml index 1bdba29..bb0a11b 100644 --- a/.github/ISSUE_TEMPLATE/tech-ed-assignment.yml +++ b/.github/ISSUE_TEMPLATE/tech-ed-assignment.yml @@ -1,80 +1,80 @@ -name: Tech Ed Coursework -description: Assign a piece of technical coursework -title: "[TECH ED] <title>" -labels: [Tech Ed, 🏕 Priority Mandatory, 🐂 Size Medium] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to assign this coursework! - - To support our trainees with planning and prioritising their own learning journey, we want our coursework assignments to be more informative. - We don't just want to tell them what to do, we want to tell them stuff like: - - why we are doing it - - what it's "for" (problem-solving, debugging, etc) - - how long they should spend on it, maximum - - how to get help - - how to review it with answers - - how to get it reviewed from mentors and peers - - type: input - attributes: - label: Link to the coursework - validations: - required: true - - type: textarea - attributes: - label: Why are we doing this? - description: Clearly explain the purpose of this assignment - validations: - required: true - - type: input - attributes: - label: Maximum time in hours - description: (Tech has max 16 per week total) - validations: - required: true - - type: textarea - attributes: - label: How to get help - description: State simply how trainees can get help with this assignment - placeholder: | - Share your blockers in your class channel - https://syllabus.codeyourfuture.io/guides/asking-questions - - type: textarea - attributes: - label: How to submit - description: State in clear steps how a trainee can submit this assignment. - placeholder: | - Fork the repo to your own GitHub account - Make regular small commits with clear messages - When you are ready, open a Pull Request to the CYF repo - Make sure you fill in the PR template provided - validations: - required: true - - type: textarea - attributes: - label: How to review - description: How to get code review and how to self-review - - type: textarea - attributes: - label: Anything else? - description: | - Links? References? Anything that will give more context - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - - type: markdown - attributes: - value: | - **Thank you so much.** - - Please now complete this ticket by filling in the options on the sidebar. - - 1. Update labels - - priority -- is this coursework key, mandatory, or stretch? Pick one. - - size -- help trainees plan their time with rough estimation. Pick one - - topics -- add all that seem relevant to you. - 2. Add to milestone - - week 1,2,3,4 - - Once your ticket is complete, you may like to add it to the example project board attached to this repo. - This is so you understand how trainees will use your work. Nobody has built a board copier yet, so trainees will be doing this step themselves. +name: Tech Ed Coursework +description: Assign a piece of technical coursework +title: "[TECH ED] <title>" +labels: [Tech Ed, 🏕 Priority Mandatory, 🐂 Size Medium] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to assign this coursework! + + To support our trainees with planning and prioritising their own learning journey, we want our coursework assignments to be more informative. + We don't just want to tell them what to do, we want to tell them stuff like: + - why we are doing it + - what it's "for" (problem-solving, debugging, etc) + - how long they should spend on it, maximum + - how to get help + - how to review it with answers + - how to get it reviewed from mentors and peers + - type: input + attributes: + label: Link to the coursework + validations: + required: true + - type: textarea + attributes: + label: Why are we doing this? + description: Clearly explain the purpose of this assignment + validations: + required: true + - type: input + attributes: + label: Maximum time in hours + description: (Tech has max 16 per week total) + validations: + required: true + - type: textarea + attributes: + label: How to get help + description: State simply how trainees can get help with this assignment + placeholder: | + Share your blockers in your class channel + https://syllabus.codeyourfuture.io/guides/asking-questions + - type: textarea + attributes: + label: How to submit + description: State in clear steps how a trainee can submit this assignment. + placeholder: | + Fork the repo to your own GitHub account + Make regular small commits with clear messages + When you are ready, open a Pull Request to the CYF repo + Make sure you fill in the PR template provided + validations: + required: true + - type: textarea + attributes: + label: How to review + description: How to get code review and how to self-review + - type: textarea + attributes: + label: Anything else? + description: | + Links? References? Anything that will give more context + + Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. + - type: markdown + attributes: + value: | + **Thank you so much.** + + Please now complete this ticket by filling in the options on the sidebar. + + 1. Update labels + - priority -- is this coursework key, mandatory, or stretch? Pick one. + - size -- help trainees plan their time with rough estimation. Pick one + - topics -- add all that seem relevant to you. + 2. Add to milestone + - week 1,2,3,4 + + Once your ticket is complete, you may like to add it to the example project board attached to this repo. + This is so you understand how trainees will use your work. Nobody has built a board copier yet, so trainees will be doing this step themselves. diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index e3ae612..01d0b3a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,32 +1,32 @@ -<!-- - -You must title your PR like this: - -REGION | COHORT_NAME | FIRST_NAME LAST_NAME | SPRINT NUM | PROJECT NAME - -For example, - -LONDON | ITP-May-26 | Jane Doe | Sprint 4 | Project TV Show - -Complete the task list below this message. -If your PR is rejected, check the task list. - ---> - -## Learners, PR Template - -Self checklist - -- [ ] I have committed my files one by one, on purpose, and for a reason -- [ ] I have titled my PR with REGION | COHORT_NAME | FIRST_NAME LAST_NAME | SPRINT NUM | PROJECT NAME -- [ ] I have tested my changes -- [ ] My changes follow the [style guide](https://syllabus.codeyourfuture.io/guides/code-style-guide/) -- [ ] My changes meet the [requirements](./README.md) of this task - -## Changelist - -Briefly explain your PR. - -## Questions - -Ask any questions you have for your reviewer. +<!-- + +You must title your PR like this: + +REGION | COHORT_NAME | FIRST_NAME LAST_NAME | SPRINT NUM | PROJECT NAME + +For example, + +LONDON | ITP-May-26 | Jane Doe | Sprint 4 | Project TV Show + +Complete the task list below this message. +If your PR is rejected, check the task list. + +--> + +## Learners, PR Template + +Self checklist + +- [ ] I have committed my files one by one, on purpose, and for a reason +- [ ] I have titled my PR with REGION | COHORT_NAME | FIRST_NAME LAST_NAME | SPRINT NUM | PROJECT NAME +- [ ] I have tested my changes +- [ ] My changes follow the [style guide](https://syllabus.codeyourfuture.io/guides/code-style-guide/) +- [ ] My changes meet the [requirements](./README.md) of this task + +## Changelist + +Briefly explain your PR. + +## Questions + +Ask any questions you have for your reviewer. diff --git a/HOW_TO_REVIEW.md b/HOW_TO_REVIEW.md index 1afda18..8f78199 100644 --- a/HOW_TO_REVIEW.md +++ b/HOW_TO_REVIEW.md @@ -1,66 +1,66 @@ -<!-- -Do not edit this file. -Make a change to the template and then pull changes -Repo: https://github.com/CodeYourFuture/Module-Template ---> - -# Everyone reviews code at CYF - -Mentors and trainees all review code, and collaborate on improving code quality. We are all helping each other to talk, write, and think about code more clearly. - -We are not reviewing code as if we were to merge this PR into production; we are opening a technical conversation for the purpose of insight and development. - -## Key points: - -1. Ask questions instead of making statements: - - **YES:** "Is there another element you could use to group a set of fields in a form? Why might someone use a different element in a form?" - **NO:** "Use fieldset not divs" - -2. Encourage simplicity, clarity, and precision: - - **YES** "There are 15,0000 files in this changelist. Which files should be reviewed?" - **NO** "It doesn't matter; I can try to figure out what you meant." - -3. Respect everyone's work and time: - - **YES** "I think there's some more to do here. Thanks for sharing where you're up to." - **NO** "This is rubbish. Try harder." - -## Labels - -Reviewers, please add labels (provided) to the PR once you've reviewed. This helps to focus the trainee on the areas they should work on, and gives an overview for mentors on what the whole cohort needs to work on. - -## Solutions - -### Where to find solutions? - -You can find the solutions for the module on the `solutions` branch. - -### Solutions branch - -The solutions branch typically contains: - -#### Sample solutions - -Solutions are example answers not the only correct answers. - -#### Common responses guides. - -Everyone is invited to contribute commonly encountered problems, mistakes, misunderstandings, and mental-model errors to our common responses documents. - -Use these resources to inform your code review, get unstuck, and improve your understanding. - -## Guides - -Here's a detailed checklist of the sorts of things we should check code for: - -https://syllabus.codeyourfuture.io/guides/marking-guide - -Here's a detailed style guide to help us all write clear, high quality code: - -https://syllabus.codeyourfuture.io/guides/code-style-guide - -Here's some help with giving good feedback during code review: - -https://teachertraining.codeyourfuture.io/tasks/code-review +<!-- +Do not edit this file. +Make a change to the template and then pull changes +Repo: https://github.com/CodeYourFuture/Module-Template +--> + +# Everyone reviews code at CYF + +Mentors and trainees all review code, and collaborate on improving code quality. We are all helping each other to talk, write, and think about code more clearly. + +We are not reviewing code as if we were to merge this PR into production; we are opening a technical conversation for the purpose of insight and development. + +## Key points: + +1. Ask questions instead of making statements: + + **YES:** "Is there another element you could use to group a set of fields in a form? Why might someone use a different element in a form?" + **NO:** "Use fieldset not divs" + +2. Encourage simplicity, clarity, and precision: + + **YES** "There are 15,0000 files in this changelist. Which files should be reviewed?" + **NO** "It doesn't matter; I can try to figure out what you meant." + +3. Respect everyone's work and time: + + **YES** "I think there's some more to do here. Thanks for sharing where you're up to." + **NO** "This is rubbish. Try harder." + +## Labels + +Reviewers, please add labels (provided) to the PR once you've reviewed. This helps to focus the trainee on the areas they should work on, and gives an overview for mentors on what the whole cohort needs to work on. + +## Solutions + +### Where to find solutions? + +You can find the solutions for the module on the `solutions` branch. + +### Solutions branch + +The solutions branch typically contains: + +#### Sample solutions + +Solutions are example answers not the only correct answers. + +#### Common responses guides. + +Everyone is invited to contribute commonly encountered problems, mistakes, misunderstandings, and mental-model errors to our common responses documents. + +Use these resources to inform your code review, get unstuck, and improve your understanding. + +## Guides + +Here's a detailed checklist of the sorts of things we should check code for: + +https://syllabus.codeyourfuture.io/guides/marking-guide + +Here's a detailed style guide to help us all write clear, high quality code: + +https://syllabus.codeyourfuture.io/guides/code-style-guide + +Here's some help with giving good feedback during code review: + +https://teachertraining.codeyourfuture.io/tasks/code-review diff --git a/contributing.md b/contributing.md index 6540972..a9e21c1 100644 --- a/contributing.md +++ b/contributing.md @@ -1,25 +1,25 @@ -<!-- -Do not edit this file. -Make a change to the template and then pull changes -Repo: https://github.com/CodeYourFuture/Module-Template ---> - -# How To Submit Your Coursework - -Use Git & Github to submit your coursework as a pull request. - -The Github Desktop cheatsheet will help you. - -[Github Desktop Cheatsheet](http://syllabus.codeyourfuture.io/git/cheatsheet) - -This module will help you submit your coursework. - -[Git](http://syllabus.codeyourfuture.io/git/index) - -## Questions & Help - -Contributing to a remote codebase is a necessary skill for a professional developer. Opening PRs is mandatory at CYF. It is part of the coursework. - -If you cannot submit your coursework you **must** post on Slack to get unblocked. - -[How to get help](./HOW-TO-GET-HELP.md) +<!-- +Do not edit this file. +Make a change to the template and then pull changes +Repo: https://github.com/CodeYourFuture/Module-Template +--> + +# How To Submit Your Coursework + +Use Git & Github to submit your coursework as a pull request. + +The Github Desktop cheatsheet will help you. + +[Github Desktop Cheatsheet](http://syllabus.codeyourfuture.io/git/cheatsheet) + +This module will help you submit your coursework. + +[Git](http://syllabus.codeyourfuture.io/git/index) + +## Questions & Help + +Contributing to a remote codebase is a necessary skill for a professional developer. Opening PRs is mandatory at CYF. It is part of the coursework. + +If you cannot submit your coursework you **must** post on Slack to get unblocked. + +[How to get help](./HOW-TO-GET-HELP.md) diff --git a/episodes.js b/episodes.js deleted file mode 100644 index 5ef6e9e..0000000 --- a/episodes.js +++ /dev/null @@ -1,1855 +0,0 @@ -//DO NOT EDIT THIS FILE - -//This content is from https://www.tvmaze.com/ -//specifically: https://api.tvmaze.com/shows/82/episodes - -function getOneEpisode() { - return { - id: 4952, - url: - "http://www.tvmaze.com/episodes/4952/game-of-thrones-1x01-winter-is-coming", - name: "Winter is Coming", - season: 1, - number: 1, - airdate: "2011-04-17", - airtime: "21:00", - airstamp: "2011-04-18T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2668.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2668.jpg", - }, - summary: - "<p>Lord Eddard Stark, ruler of the North, is summoned to court by his old friend, King Robert Baratheon, to serve as the King's Hand. Eddard reluctantly agrees after learning of a possible threat to the King's life. Eddard's bastard son Jon Snow must make a painful decision about his own future, while in the distant east Viserys Targaryen plots to reclaim his father's throne, usurped by Robert, by selling his sister in marriage.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4952", - }, - }, - }; -} - -function getAllEpisodes() { - return [ - { - id: 4952, - url: - "http://www.tvmaze.com/episodes/4952/game-of-thrones-1x01-winter-is-coming", - name: "Winter is Coming", - season: 1, - number: 1, - airdate: "2011-04-17", - airtime: "21:00", - airstamp: "2011-04-18T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2668.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2668.jpg", - }, - summary: - "<p>Lord Eddard Stark, ruler of the North, is summoned to court by his old friend, King Robert Baratheon, to serve as the King's Hand. Eddard reluctantly agrees after learning of a possible threat to the King's life. Eddard's bastard son Jon Snow must make a painful decision about his own future, while in the distant east Viserys Targaryen plots to reclaim his father's throne, usurped by Robert, by selling his sister in marriage.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4952", - }, - }, - }, - { - id: 4953, - url: - "http://www.tvmaze.com/episodes/4953/game-of-thrones-1x02-the-kingsroad", - name: "The Kingsroad", - season: 1, - number: 2, - airdate: "2011-04-24", - airtime: "21:00", - airstamp: "2011-04-25T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2669.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2669.jpg", - }, - summary: - "<p>An incident on the Kingsroad threatens Eddard and Robert's friendship. Jon and Tyrion travel to the Wall, where they discover that the reality of the Night's Watch may not match the heroic image of it.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4953", - }, - }, - }, - { - id: 4954, - url: "http://www.tvmaze.com/episodes/4954/game-of-thrones-1x03-lord-snow", - name: "Lord Snow", - season: 1, - number: 3, - airdate: "2011-05-01", - airtime: "21:00", - airstamp: "2011-05-02T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2671.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2671.jpg", - }, - summary: - "<p>Jon Snow attempts to find his place amongst the Night's Watch. Eddard and his daughters arrive at King's Landing.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4954", - }, - }, - }, - { - id: 4955, - url: - "http://www.tvmaze.com/episodes/4955/game-of-thrones-1x04-cripples-bastards-and-broken-things", - name: "Cripples, Bastards, and Broken Things", - season: 1, - number: 4, - airdate: "2011-05-08", - airtime: "21:00", - airstamp: "2011-05-09T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2673.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2673.jpg", - }, - summary: - "<p>Tyrion stops at Winterfell on his way home and gets a frosty reception from Robb Stark. Eddard's investigation into the death of his predecessor gets underway.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4955", - }, - }, - }, - { - id: 4956, - url: - "http://www.tvmaze.com/episodes/4956/game-of-thrones-1x05-the-wolf-and-the-lion", - name: "The Wolf and the Lion", - season: 1, - number: 5, - airdate: "2011-05-15", - airtime: "21:00", - airstamp: "2011-05-16T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2674.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2674.jpg", - }, - summary: - "<p>Catelyn's actions on the road have repercussions for Eddard. Tyrion enjoys the dubious hospitality of the Eyrie.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4956", - }, - }, - }, - { - id: 4957, - url: - "http://www.tvmaze.com/episodes/4957/game-of-thrones-1x06-a-golden-crown", - name: "A Golden Crown", - season: 1, - number: 6, - airdate: "2011-05-22", - airtime: "21:00", - airstamp: "2011-05-23T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2676.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2676.jpg", - }, - summary: - "<p>Viserys is increasingly frustrated by the lack of progress towards gaining his crown.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4957", - }, - }, - }, - { - id: 4958, - url: - "http://www.tvmaze.com/episodes/4958/game-of-thrones-1x07-you-win-or-you-die", - name: "You Win or You Die", - season: 1, - number: 7, - airdate: "2011-05-29", - airtime: "21:00", - airstamp: "2011-05-30T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2677.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2677.jpg", - }, - summary: - "<p>Eddard's investigations in King's Landing reach a climax and a dark secret is revealed.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4958", - }, - }, - }, - { - id: 4959, - url: - "http://www.tvmaze.com/episodes/4959/game-of-thrones-1x08-the-pointy-end", - name: "The Pointy End", - season: 1, - number: 8, - airdate: "2011-06-05", - airtime: "21:00", - airstamp: "2011-06-06T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2678.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2678.jpg", - }, - summary: - "<p>Tyrion joins his father's army with unexpected allies. Events in King's Landing take a turn for the worse as Arya's lessons are put to the test.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4959", - }, - }, - }, - { - id: 4960, - url: "http://www.tvmaze.com/episodes/4960/game-of-thrones-1x09-baelor", - name: "Baelor", - season: 1, - number: 9, - airdate: "2011-06-12", - airtime: "21:00", - airstamp: "2011-06-13T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2679.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2679.jpg", - }, - summary: - "<p>Catelyn must negotiate with the irascible Lord Walder Frey.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4960", - }, - }, - }, - { - id: 4961, - url: - "http://www.tvmaze.com/episodes/4961/game-of-thrones-1x10-fire-and-blood", - name: "Fire and Blood", - season: 1, - number: 10, - airdate: "2011-06-19", - airtime: "21:00", - airstamp: "2011-06-20T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2681.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2681.jpg", - }, - summary: - "<p>Daenerys must realize her destiny. Jaime finds himself in an unfamiliar predicament.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4961", - }, - }, - }, - { - id: 4962, - url: - "http://www.tvmaze.com/episodes/4962/game-of-thrones-2x01-the-north-remembers", - name: "The North Remembers", - season: 2, - number: 1, - airdate: "2012-04-01", - airtime: "21:00", - airstamp: "2012-04-02T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3174.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3174.jpg", - }, - summary: - "<p>War grips the continent of Westeros. As Tyrion Lannister tries to take his strong-willed nephew in hand in King's Landing, Stannis Baratheon launches his own campaign to take the Iron Throne with the help of a mysterious priestess. In the east, Daenerys must lead her retinue through a desolate wasteland whilst beyond the Wall the Night's Watch seeks the aid of a wildling.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4962", - }, - }, - }, - { - id: 4963, - url: - "http://www.tvmaze.com/episodes/4963/game-of-thrones-2x02-the-night-lands", - name: "The Night Lands", - season: 2, - number: 2, - airdate: "2012-04-08", - airtime: "21:00", - airstamp: "2012-04-09T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3175.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3175.jpg", - }, - summary: - "<p>Stannis uses Ser Davos to seek out new allies for his war with the Lannisters. On the road north, Arya confides in Gendry. Robb Stark sends Theon Greyjoy to win an alliance with his father and the fierce warriors of the Iron Islands. Cersei and Tyrion clash on how to rule in King's Landing.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4963", - }, - }, - }, - { - id: 4964, - url: - "http://www.tvmaze.com/episodes/4964/game-of-thrones-2x03-what-is-dead-may-never-die", - name: "What is Dead May Never Die", - season: 2, - number: 3, - airdate: "2012-04-15", - airtime: "21:00", - airstamp: "2012-04-16T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3176.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3176.jpg", - }, - summary: - "<p>Catelyn Stark treats with King Renly in the hope of winning an alliance. Tyrion undertakes a complex plan in King's Landing to expose an enemy. At Winterfell, Bran's dreams continue to trouble him.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4964", - }, - }, - }, - { - id: 4965, - url: - "http://www.tvmaze.com/episodes/4965/game-of-thrones-2x04-garden-of-bones", - name: "Garden of Bones", - season: 2, - number: 4, - airdate: "2012-04-22", - airtime: "21:00", - airstamp: "2012-04-23T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3177.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3177.jpg", - }, - summary: - "<p>Tyrion attempts to restrain Joffrey's cruelty. Catelyn attempts to broker a peace between Stannis and Renly. Daenerys and her followers arrive at the great city of Qarth and hope to find refuge there. Arya and Gendry arrive at Harrenhal, a great castle now under Lannister occupation.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4965", - }, - }, - }, - { - id: 4966, - url: - "http://www.tvmaze.com/episodes/4966/game-of-thrones-2x05-the-ghost-of-harrenhal", - name: "The Ghost of Harrenhal", - season: 2, - number: 5, - airdate: "2012-04-29", - airtime: "21:00", - airstamp: "2012-04-30T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3178.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3178.jpg", - }, - summary: - "<p>Confusion rages in the Stormlands in the wake of a devastating reversal. Catelyn must flee with a new ally, whilst Littlefinger sees an opportunity in the chaos. Theon seeks to prove himself to his father in battle. Arya receives a promise from the enigmatic Jaqen H'ghar. The Night's Watch arrives at the Fist of the First Men. Daenerys Targaryen receives a marriage proposal.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4966", - }, - }, - }, - { - id: 4967, - url: - "http://www.tvmaze.com/episodes/4967/game-of-thrones-2x06-the-old-gods-and-the-new", - name: "The Old Gods and the New", - season: 2, - number: 6, - airdate: "2012-05-06", - airtime: "21:00", - airstamp: "2012-05-07T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3180.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3180.jpg", - }, - summary: - "<p>Arya has a surprise visitor; Dany vows to take what is hers; Joffrey meets his subjects; Qhorin gives Jon a chance to prove himself.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4967", - }, - }, - }, - { - id: 4968, - url: - "http://www.tvmaze.com/episodes/4968/game-of-thrones-2x07-a-man-without-honor", - name: "A Man Without Honor", - season: 2, - number: 7, - airdate: "2012-05-13", - airtime: "21:00", - airstamp: "2012-05-14T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3192.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3192.jpg", - }, - summary: - "<p>Jaime meets a relative; Theon hunts; Dany receives an invitation.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4968", - }, - }, - }, - { - id: 4969, - url: - "http://www.tvmaze.com/episodes/4969/game-of-thrones-2x08-the-prince-of-winterfell", - name: "The Prince of Winterfell", - season: 2, - number: 8, - airdate: "2012-05-20", - airtime: "21:00", - airstamp: "2012-05-21T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3194.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3194.jpg", - }, - summary: - "<p>Theon holds the fort; Arya calls in her debt with Jaqen; Robb is betrayed; Stannis and Davos approach their destination.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4969", - }, - }, - }, - { - id: 4970, - url: - "http://www.tvmaze.com/episodes/4970/game-of-thrones-2x09-blackwater", - name: "Blackwater", - season: 2, - number: 9, - airdate: "2012-05-27", - airtime: "21:00", - airstamp: "2012-05-28T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3196.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3196.jpg", - }, - summary: - "<p>A massive battle rages for control of King's Landing and the Iron Throne.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4970", - }, - }, - }, - { - id: 4971, - url: - "http://www.tvmaze.com/episodes/4971/game-of-thrones-2x10-valar-morghulis", - name: "Valar Morghulis", - season: 2, - number: 10, - airdate: "2012-06-03", - airtime: "21:00", - airstamp: "2012-06-04T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/3197.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/3197.jpg", - }, - summary: - "<p>Tyrion awakens to a changed situation. King Joffrey doles out rewards to his subjects. As Theon stirs his men to action, Luwin offers some final advice. Brienne silences Jaime; Arya receives a gift from Jaqen; Dany goes to a strange place; Jon proves himself to Qhorin.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4971", - }, - }, - }, - { - id: 4972, - url: - "http://www.tvmaze.com/episodes/4972/game-of-thrones-3x01-valar-dohaeris", - name: "Valar Dohaeris", - season: 3, - number: 1, - airdate: "2013-03-31", - airtime: "21:00", - airstamp: "2013-04-01T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2628.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2628.jpg", - }, - summary: - "<p></p><p>Jon is brought before Mance Rayder, the King Beyond the Wall, while the Night's Watch survivors retreat south. In King's Landing, Tyrion asks for his reward. Littlefinger offers Sansa a way out. Cersei hosts a dinner for the royal family. Daenerys sails into Slaver's Bay.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4972", - }, - }, - }, - { - id: 4973, - url: - "http://www.tvmaze.com/episodes/4973/game-of-thrones-3x02-dark-wings-dark-words", - name: "Dark Wings, Dark Words", - season: 3, - number: 2, - airdate: "2013-04-07", - airtime: "21:00", - airstamp: "2013-04-08T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2618.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2618.jpg", - }, - summary: - "<p>Sansa says too much. Shae asks Tyrion for a favor. Jaime finds a way to pass the time. Arya runs into the Brotherhood Without Banners.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4973", - }, - }, - }, - { - id: 4974, - url: - "http://www.tvmaze.com/episodes/4974/game-of-thrones-3x03-walk-of-punishment", - name: "Walk of Punishment", - season: 3, - number: 3, - airdate: "2013-04-14", - airtime: "21:00", - airstamp: "2013-04-15T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2616.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2616.jpg", - }, - summary: - "<p>Tyrion shoulders new responsibilities. Jon is taken to the Fist of the First Men. Daenerys meets with the slavers. Jaime strikes a deal with his captors.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4974", - }, - }, - }, - { - id: 4975, - url: - "http://www.tvmaze.com/episodes/4975/game-of-thrones-3x04-and-now-his-watch-is-ended", - name: "And Now His Watch is Ended", - season: 3, - number: 4, - airdate: "2013-04-21", - airtime: "21:00", - airstamp: "2013-04-22T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2615.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2615.jpg", - }, - summary: - "<p>The Night's Watch takes stock. Varys meets his better. Arya is taken to the commander of the Brotherhood. Daenerys exchanges a chain for a Whip.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4975", - }, - }, - }, - { - id: 4976, - url: - "http://www.tvmaze.com/episodes/4976/game-of-thrones-3x05-kissed-by-fire", - name: "Kissed by Fire", - season: 3, - number: 5, - airdate: "2013-04-28", - airtime: "21:00", - airstamp: "2013-04-29T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2614.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2614.jpg", - }, - summary: - "<p>The Hound is judged by the gods; Jaime is judged by men. Jon proves himself; Robb is betrayed. Tyrion learns the cost of weddings.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4976", - }, - }, - }, - { - id: 4977, - url: "http://www.tvmaze.com/episodes/4977/game-of-thrones-3x06-the-climb", - name: "The Climb", - season: 3, - number: 6, - airdate: "2013-05-05", - airtime: "21:00", - airstamp: "2013-05-06T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2612.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2612.jpg", - }, - summary: - "<p>Tywin plans strategic unions for the Lannisters. Melisandre visits the Riverlands. Robb weighs a compromise to repair his alliance with House Frey. Roose Bolton decides what to do with Jaime Lannister. Jon, Ygritte and the Wildlings face a daunting climb.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4977", - }, - }, - }, - { - id: 4978, - url: - "http://www.tvmaze.com/episodes/4978/game-of-thrones-3x07-the-bear-and-the-maiden-fair", - name: "The Bear and the Maiden Fair", - season: 3, - number: 7, - airdate: "2013-05-12", - airtime: "21:00", - airstamp: "2013-05-13T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2611.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2611.jpg", - }, - summary: - "<p>Daenerys exchanges gifts with a slave lord outside Yunkai. As Sansa frets about her prospects, Shae chafes at Tyrion's new situation. Tywin counsels the king, and Melisandre reveals a secret to Gendry. Brienne faces a formidable foe in Harrenhal.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4978", - }, - }, - }, - { - id: 4979, - url: - "http://www.tvmaze.com/episodes/4979/game-of-thrones-3x08-second-sons", - name: "Second Sons", - season: 3, - number: 8, - airdate: "2013-05-19", - airtime: "21:00", - airstamp: "2013-05-20T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2599.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2599.jpg", - }, - summary: - "<p>King's Landing hosts a wedding, and Tyrion and Sansa spend the night together. Daenerys meets the Titan's Bastard. Davos demands proof from Melisandre. Sam and Gilly meet an older Gentleman.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4979", - }, - }, - }, - { - id: 4980, - url: - "http://www.tvmaze.com/episodes/4980/game-of-thrones-3x09-the-rains-of-castamere", - name: "The Rains of Castamere", - season: 3, - number: 9, - airdate: "2013-06-02", - airtime: "21:00", - airstamp: "2013-06-03T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2598.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2598.jpg", - }, - summary: - "<p>Robb presents himself to Walder Frey, and Edmure meets his bride. Jon faces his harshest test yet. Bran discovers a new gift. Daario and Jorah debate how to take Yunkai. House Frey joins with House Tully.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4980", - }, - }, - }, - { - id: 4981, - url: "http://www.tvmaze.com/episodes/4981/game-of-thrones-3x10-mhysa", - name: "Mhysa", - season: 3, - number: 10, - airdate: "2013-06-09", - airtime: "21:00", - airstamp: "2013-06-10T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2597.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2597.jpg", - }, - summary: - "<p>Joffrey challenges Tywin. Bran tells a ghost story. In Dragonstone, mercy comes from strange quarters. Daenerys waits to see if she is a conqueror or a liberator.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4981", - }, - }, - }, - { - id: 4982, - url: - "http://www.tvmaze.com/episodes/4982/game-of-thrones-4x01-two-swords", - name: "Two Swords", - season: 4, - number: 1, - airdate: "2014-04-06", - airtime: "21:00", - airstamp: "2014-04-07T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2583.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2583.jpg", - }, - summary: - "<p>Tyrion welcomes a guest to King's Landing. At Castle Black, Jon Snow finds himself unwelcome. Dany is pointed to Meereen, the mother of all slave cities. Arya runs into an old friend.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4982", - }, - }, - }, - { - id: 4983, - url: - "http://www.tvmaze.com/episodes/4983/game-of-thrones-4x02-the-lion-and-the-rose", - name: "The Lion and the Rose", - season: 4, - number: 2, - airdate: "2014-04-13", - airtime: "21:00", - airstamp: "2014-04-14T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2584.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2584.jpg", - }, - summary: - "<p>Tyrion lends Jaime a hand. Joffrey and Margaery host a breakfast. At Dragonstone, Stannis loses patience with Davos. Ramsay finds a purpose for his pet. North of the Wall, Bran sees where they must go.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4983", - }, - }, - }, - { - id: 4984, - url: - "http://www.tvmaze.com/episodes/4984/game-of-thrones-4x03-breaker-of-chains", - name: "Breaker of Chains", - season: 4, - number: 3, - airdate: "2014-04-20", - airtime: "21:00", - airstamp: "2014-04-21T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2585.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2585.jpg", - }, - summary: - "<p>Tyrion ponders his options. Tywin extends an olive branch. Sam realizes Castle Black isn't safe, and Jon proposes a bold plan. The Hound teaches Arya the way things are. Dany chooses her Champion.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4984", - }, - }, - }, - { - id: 4985, - url: - "http://www.tvmaze.com/episodes/4985/game-of-thrones-4x04-oathkeeper", - name: "Oathkeeper", - season: 4, - number: 4, - airdate: "2014-04-27", - airtime: "21:00", - airstamp: "2014-04-28T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2586.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2586.jpg", - }, - summary: - "<p>Dany balances justice and mercy. Jaime tasks Brienne with his honor. Jon secures volunteers while Bran, Jojen, Meera and Hodor stumble on shelter.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4985", - }, - }, - }, - { - id: 4986, - url: - "http://www.tvmaze.com/episodes/4986/game-of-thrones-4x05-first-of-his-name", - name: "First of His Name", - season: 4, - number: 5, - airdate: "2014-05-04", - airtime: "21:00", - airstamp: "2014-05-05T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2587.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2587.jpg", - }, - summary: - "<p>Cersei and Tywin plot the Crown's next move. Dany discusses future plans. Jon embarks on a new mission.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4986", - }, - }, - }, - { - id: 4987, - url: - "http://www.tvmaze.com/episodes/4987/game-of-thrones-4x06-the-laws-of-gods-and-men", - name: "The Laws of Gods and Men", - season: 4, - number: 6, - airdate: "2014-05-11", - airtime: "21:00", - airstamp: "2014-05-12T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2588.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2588.jpg", - }, - summary: - "<p>Stannis and Davos set sail with a new strategy. Dany meets with supplicants. Tyrion faces down his father in the throne room.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4987", - }, - }, - }, - { - id: 4988, - url: - "http://www.tvmaze.com/episodes/4988/game-of-thrones-4x07-mockingbird", - name: "Mockingbird", - season: 4, - number: 7, - airdate: "2014-05-18", - airtime: "21:00", - airstamp: "2014-05-19T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2589.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2589.jpg", - }, - summary: - "<p>Tyrion enlists an unlikely ally. Daario entreats Dany to allow him to do what he does best. Jon's warnings about the Wall's vulnerability fall on deaf ears. Brienne follows a new lead on the road with Pod.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4988", - }, - }, - }, - { - id: 4989, - url: - "http://www.tvmaze.com/episodes/4989/game-of-thrones-4x08-the-mountain-and-the-viper", - name: "The Mountain and the Viper", - season: 4, - number: 8, - airdate: "2014-06-01", - airtime: "21:00", - airstamp: "2014-06-02T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2591.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2591.jpg", - }, - summary: - "<p>Mole's Town receives unexpected visitors. Littlefinger's motives are questioned. Ramsay attempts to prove himself to his father. Tyrion's fate is decided.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4989", - }, - }, - }, - { - id: 4990, - url: - "http://www.tvmaze.com/episodes/4990/game-of-thrones-4x09-the-watchers-on-the-wall", - name: "The Watchers on the Wall", - season: 4, - number: 9, - airdate: "2014-06-08", - airtime: "21:00", - airstamp: "2014-06-09T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2593.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2593.jpg", - }, - summary: - "<p>Jon Snow and the rest of the Night's Watch face the biggest challenge to the Wall yet.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4990", - }, - }, - }, - { - id: 4991, - url: - "http://www.tvmaze.com/episodes/4991/game-of-thrones-4x10-the-children", - name: "The Children", - season: 4, - number: 10, - airdate: "2014-06-15", - airtime: "21:00", - airstamp: "2014-06-16T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/1/2594.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/1/2594.jpg", - }, - summary: - "<p>An unexpected arrival north of the Wall changes circumstances. Dany is forced to face harsh realities. Bran learns more of his destiny. Tyrion sees the truth of his situation.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/4991", - }, - }, - }, - { - id: 116522, - url: - "http://www.tvmaze.com/episodes/116522/game-of-thrones-5x01-the-wars-to-come", - name: "The Wars to Come", - season: 5, - number: 1, - airdate: "2015-04-12", - airtime: "21:00", - airstamp: "2015-04-13T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/25988.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/25988.jpg", - }, - summary: - "<p>Varys discusses a conspiracy with Tyrion; Daenerys' rule faces a new threat; Jon finds himself between two kings; and Cersei and Jaime try to move on from Tywin's demise.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/116522", - }, - }, - }, - { - id: 144328, - url: - "http://www.tvmaze.com/episodes/144328/game-of-thrones-5x02-the-house-of-black-and-white", - name: "The House of Black and White", - season: 5, - number: 2, - airdate: "2015-04-19", - airtime: "21:00", - airstamp: "2015-04-20T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/25989.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/25989.jpg", - }, - summary: - "<p>Arya arrives in Braavos; Brienne and Podrick find danger while traveling; Cersei worries about Myrcella in Dorne when Ellaria Sand seeks revenge for Oberyn's death; Jon is tempted by Stannis.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/144328", - }, - }, - }, - { - id: 144329, - url: - "http://www.tvmaze.com/episodes/144329/game-of-thrones-5x03-high-sparrow", - name: "High Sparrow", - season: 5, - number: 3, - airdate: "2015-04-26", - airtime: "21:00", - airstamp: "2015-04-27T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/25990.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/25990.jpg", - }, - summary: - "<p>Cersei meets the High Sparrow after learning of a clergyman's embarrassing tale. Meanwhile, Davos talks to Jon about the future of Winterfell, where Ramsay Snow has just learned the identity of his future bride; Arya grows impatient doing menial tasks in the House of Black and White; and Tyrion searches for more comfortable surroundings on a long trip with Varys.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/144329", - }, - }, - }, - { - id: 144330, - url: - "http://www.tvmaze.com/episodes/144330/game-of-thrones-5x04-sons-of-the-harpy", - name: "Sons of the Harpy", - season: 5, - number: 4, - airdate: "2015-05-03", - airtime: "21:00", - airstamp: "2015-05-04T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/26444.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/26444.jpg", - }, - summary: - "<p>Margaery seeks prudent counsel. Jaime Struggles in foreign lands. Dany answers the Harpy's call.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/144330", - }, - }, - }, - { - id: 151777, - url: - "http://www.tvmaze.com/episodes/151777/game-of-thrones-5x05-kill-the-boy", - name: "Kill the Boy", - season: 5, - number: 5, - airdate: "2015-05-10", - airtime: "21:00", - airstamp: "2015-05-11T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/26819.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/26819.jpg", - }, - summary: - "<p>Dany makes a difficult decision in Meereen. Jon recruits the help of an unexpected ally. Brienne searches for Sansa. Theon remains under Ramsay's control.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/151777", - }, - }, - }, - { - id: 152766, - url: - "http://www.tvmaze.com/episodes/152766/game-of-thrones-5x06-unbowed-unbent-unbroken", - name: "Unbowed, Unbent, Unbroken", - season: 5, - number: 6, - airdate: "2015-05-17", - airtime: "21:00", - airstamp: "2015-05-18T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/10/27259.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/10/27259.jpg", - }, - summary: - "<p>Arya trains. Jorah and Tyrion run into slavers. Trystane and Myrcella make plans. Jaime and Bronn reach their destination. The Sand Snakes attack.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/152766", - }, - }, - }, - { - id: 153327, - url: - "http://www.tvmaze.com/episodes/153327/game-of-thrones-5x07-the-gift", - name: "The Gift", - season: 5, - number: 7, - airdate: "2015-05-24", - airtime: "21:00", - airstamp: "2015-05-25T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/11/27535.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/11/27535.jpg", - }, - summary: - "<p>Jon prepares for conflict. Sansa tries to talk to Theon. Brienne waits for a sign. Stannis remains stubborn. Jaime attempts to reconnect with family.</p><p><br><br></p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/153327", - }, - }, - }, - { - id: 155299, - url: - "http://www.tvmaze.com/episodes/155299/game-of-thrones-5x08-hardhome", - name: "Hardhome", - season: 5, - number: 8, - airdate: "2015-05-31", - airtime: "21:00", - airstamp: "2015-06-01T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/11/28151.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/11/28151.jpg", - }, - summary: - "<p>Arya makes progress in her training. Sansa confronts an old friend. Cersei struggles. Jon travels.</p><p><br><br></p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/155299", - }, - }, - }, - { - id: 160040, - url: - "http://www.tvmaze.com/episodes/160040/game-of-thrones-5x09-the-dance-of-dragons", - name: "The Dance of Dragons", - season: 5, - number: 9, - airdate: "2015-06-07", - airtime: "21:00", - airstamp: "2015-06-08T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/11/29160.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/11/29160.jpg", - }, - summary: - "<p>Stannis confronts a troubling decision. Jon returns to The Wall. Mace visits the Iron Bank. Arya encounters someone from her past. Dany reluctantly oversees a traditional celebration of athleticism.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/160040", - }, - }, - }, - { - id: 162186, - url: - "http://www.tvmaze.com/episodes/162186/game-of-thrones-5x10-mothers-mercy", - name: "Mother's Mercy", - season: 5, - number: 10, - airdate: "2015-06-14", - airtime: "21:00", - airstamp: "2015-06-15T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/12/30012.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/12/30012.jpg", - }, - summary: - "<p>Cersei seeks forgiveness; Jon faces a new challenge; Arya plots to cross a name off her list; Tyrion sees a familiar face; and Daenerys finds herself surrounded by strangers.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/162186", - }, - }, - }, - { - id: 560813, - url: - "http://www.tvmaze.com/episodes/560813/game-of-thrones-6x01-the-red-woman", - name: "The Red Woman", - season: 6, - number: 1, - airdate: "2016-04-24", - airtime: "21:00", - airstamp: "2016-04-25T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/56/142371.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/56/142371.jpg", - }, - summary: - "<p>Jon Snow is dead. Daenerys meets a strong man. Cersei sees her daughter again.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/560813", - }, - }, - }, - { - id: 664672, - url: "http://www.tvmaze.com/episodes/664672/game-of-thrones-6x02-home", - name: "Home", - season: 6, - number: 2, - airdate: "2016-05-01", - airtime: "21:00", - airstamp: "2016-05-02T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/56/142372.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/56/142372.jpg", - }, - summary: - "<p>Bran trains with the Three-Eyed Raven. In King's Landing, Jaime advises Tommen. Tyrion demands good news, but has to make his own. At Castle Black, the Night's Watch stands behind Thorne. Ramsay Bolton proposes a plan, and Balon Greyjoy entertains other proposals.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/664672", - }, - }, - }, - { - id: 664673, - url: - "http://www.tvmaze.com/episodes/664673/game-of-thrones-6x03-oathbreaker", - name: "Oathbreaker", - season: 6, - number: 3, - airdate: "2016-05-08", - airtime: "21:00", - airstamp: "2016-05-09T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/56/142370.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/56/142370.jpg", - }, - summary: - "<p>Daenerys meets her future. Bran meets the past. Tommen confronts the High Sparrow. Arya trains to be No One. Varys finds an answer. Ramsay gets a gift.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/664673", - }, - }, - }, - { - id: 664674, - url: - "http://www.tvmaze.com/episodes/664674/game-of-thrones-6x04-book-of-the-stranger", - name: "Book of the Stranger", - season: 6, - number: 4, - airdate: "2016-05-15", - airtime: "21:00", - airstamp: "2016-05-16T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/56/142273.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/56/142273.jpg", - }, - summary: - "<p>Tyrion strikes a deal. Jorah and Daario undertake a difficult task. Jaime and Cersei try to improve their situation.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/664674", - }, - }, - }, - { - id: 664675, - url: - "http://www.tvmaze.com/episodes/664675/game-of-thrones-6x05-the-door", - name: "The Door", - season: 6, - number: 5, - airdate: "2016-05-22", - airtime: "21:00", - airstamp: "2016-05-23T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/60/150273.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/60/150273.jpg", - }, - summary: - "<p>Tyrion seeks a strange ally. Bran learns a great deal. Brienne goes on a mission. Arya is given a chance to prove herself.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/664675", - }, - }, - }, - { - id: 664676, - url: - "http://www.tvmaze.com/episodes/664676/game-of-thrones-6x06-blood-of-my-blood", - name: "Blood of My Blood", - season: 6, - number: 6, - airdate: "2016-05-29", - airtime: "21:00", - airstamp: "2016-05-30T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/60/150274.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/60/150274.jpg", - }, - summary: - "<p>An old foe comes back into the picture. Gilly meets Sam's family. Arya faces a difficult choice. Jaime faces off against the High Sparrow.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/664676", - }, - }, - }, - { - id: 717449, - url: - "http://www.tvmaze.com/episodes/717449/game-of-thrones-6x07-the-broken-man", - name: "The Broken Man", - season: 6, - number: 7, - airdate: "2016-06-05", - airtime: "21:00", - airstamp: "2016-06-06T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/60/150275.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/60/150275.jpg", - }, - summary: - "<p>The High Sparrow eyes another target. Jaime confronts a hero. Arya makes a plan. The North is reminded.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/717449", - }, - }, - }, - { - id: 729573, - url: "http://www.tvmaze.com/episodes/729573/game-of-thrones-6x08-no-one", - name: "No One", - season: 6, - number: 8, - airdate: "2016-06-12", - airtime: "21:00", - airstamp: "2016-06-13T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/61/153044.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/61/153044.jpg", - }, - summary: - "<p>Jaime encounters a hero; the High Sparrow fixates on another prey; Arya hatches a new plan; Yara and Theon plot their next move; Olenna and Cersei discuss their families' futures.</p><p></p><p>While Jaime weighs his options, Cersei answers a request. Tyrion's plans bear fruit. Arya faces a new test.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/729573", - }, - }, - }, - { - id: 729574, - url: - "http://www.tvmaze.com/episodes/729574/game-of-thrones-6x09-battle-of-the-bastards", - name: "Battle of the Bastards", - season: 6, - number: 9, - airdate: "2016-06-19", - airtime: "21:00", - airstamp: "2016-06-20T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/62/155042.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/62/155042.jpg", - }, - summary: - "<p>Ramsay surprises his audience. Jon retaliates. Dany is true to her word.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/729574", - }, - }, - }, - { - id: 729575, - url: - "http://www.tvmaze.com/episodes/729575/game-of-thrones-6x10-the-winds-of-winter", - name: "The Winds of Winter", - season: 6, - number: 10, - airdate: "2016-06-26", - airtime: "21:00", - airstamp: "2016-06-27T01:00:00+00:00", - runtime: 69, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/63/157920.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/63/157920.jpg", - }, - summary: - "<p>Alliances are made, the High Sparrow is holding trials at King's Landing, Daenerys is sailing for the Seven Kingdoms and a new King of the North is crowned.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/729575", - }, - }, - }, - { - id: 937256, - url: - "http://www.tvmaze.com/episodes/937256/game-of-thrones-7x01-dragonstone", - name: "Dragonstone", - season: 7, - number: 1, - airdate: "2017-07-16", - airtime: "21:00", - airstamp: "2017-07-17T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/120/302038.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/120/302038.jpg", - }, - summary: - "<p>Jon organizes the defense of the North. Cersei tries to even the odds. Daenerys comes home.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/937256", - }, - }, - }, - { - id: 1221410, - url: - "http://www.tvmaze.com/episodes/1221410/game-of-thrones-7x02-stormborn", - name: "Stormborn", - season: 7, - number: 2, - airdate: "2017-07-23", - airtime: "21:00", - airstamp: "2017-07-24T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/120/302047.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/120/302047.jpg", - }, - summary: - "<p>Daenerys receives an unexpected visitor. Jon faces a revolt. Tyrion plans the conquest of Westeros.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221410", - }, - }, - }, - { - id: 1221411, - url: - "http://www.tvmaze.com/episodes/1221411/game-of-thrones-7x03-the-queens-justice", - name: "The Queen's Justice", - season: 7, - number: 3, - airdate: "2017-07-30", - airtime: "21:00", - airstamp: "2017-07-31T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/122/306938.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/122/306938.jpg", - }, - summary: - "<p>Daenerys holds court. Cersei returns a gift. Jaime learns from his mistakes.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221411", - }, - }, - }, - { - id: 1221412, - url: - "http://www.tvmaze.com/episodes/1221412/game-of-thrones-7x04-the-spoils-of-war", - name: "The Spoils of War", - season: 7, - number: 4, - airdate: "2017-08-06", - airtime: "21:00", - airstamp: "2017-08-07T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/123/307677.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/123/307677.jpg", - }, - summary: - "<p>Arya gets to the final destination. Daenerys takes it upon herself to strike back.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221412", - }, - }, - }, - { - id: 1221413, - url: - "http://www.tvmaze.com/episodes/1221413/game-of-thrones-7x05-eastwatch", - name: "Eastwatch", - season: 7, - number: 5, - airdate: "2017-08-13", - airtime: "21:00", - airstamp: "2017-08-14T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/124/310839.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/124/310839.jpg", - }, - summary: - "<p>Daenerys demands loyalty from the surviving Lannister soldiers; Jon heeds Bran's warning about White Walkers on the move; Cersei vows to vanquish anyone or anything that stands in her way.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221413", - }, - }, - }, - { - id: 1221414, - url: - "http://www.tvmaze.com/episodes/1221414/game-of-thrones-7x06-beyond-the-wall", - name: "Beyond the Wall", - season: 7, - number: 6, - airdate: "2017-08-20", - airtime: "21:00", - airstamp: "2017-08-21T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/125/312651.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/125/312651.jpg", - }, - summary: - "<p>Jon's mission continues north of the wall, but the odds against his ragged band of misfits may be greater than he imagined.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221414", - }, - }, - }, - { - id: 1221415, - url: - "http://www.tvmaze.com/episodes/1221415/game-of-thrones-7x07-the-dragon-and-the-wolf", - name: "The Dragon and the Wolf", - season: 7, - number: 7, - airdate: "2017-08-27", - airtime: "21:00", - airstamp: "2017-08-28T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/125/314502.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/125/314502.jpg", - }, - summary: - "<p>Cersei sits on the Iron Throne; Daenerys sails across the Narrow Sea; Jon Snow is King in the North, and winter is finally here.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1221415", - }, - }, - }, - { - id: 1590943, - url: - "http://www.tvmaze.com/episodes/1590943/game-of-thrones-8x01-winterfell", - name: "Winterfell", - season: 8, - number: 1, - airdate: "2019-04-14", - airtime: "21:00", - airstamp: "2019-04-15T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/191/479477.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/191/479477.jpg", - }, - summary: - "<p>Arriving at Winterfell, Jon and Daenerys struggle to unite a divided North. Jon gets some big news.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1590943", - }, - }, - }, - { - id: 1623964, - url: - "http://www.tvmaze.com/episodes/1623964/game-of-thrones-8x02-a-knight-of-the-seven-kingdoms", - name: "A Knight of the Seven Kingdoms", - season: 8, - number: 2, - airdate: "2019-04-21", - airtime: "21:00", - airstamp: "2019-04-22T01:00:00+00:00", - runtime: 60, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/192/482451.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/192/482451.jpg", - }, - summary: - "<p>Jaime faces judgement and Winterfell prepares for the battle to come.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1623964", - }, - }, - }, - { - id: 1623965, - url: - "http://www.tvmaze.com/episodes/1623965/game-of-thrones-8x03-the-long-night", - name: "The Long Night", - season: 8, - number: 3, - airdate: "2019-04-28", - airtime: "21:00", - airstamp: "2019-04-29T01:00:00+00:00", - runtime: 90, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/192/482465.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/192/482465.jpg", - }, - summary: "<p>Winterfell fights the Army of the Dead.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1623965", - }, - }, - }, - { - id: 1623966, - url: - "http://www.tvmaze.com/episodes/1623966/game-of-thrones-8x04-the-last-of-the-starks", - name: "The Last of the Starks", - season: 8, - number: 4, - airdate: "2019-05-05", - airtime: "21:00", - airstamp: "2019-05-06T01:00:00+00:00", - runtime: 78, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/195/487839.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/195/487839.jpg", - }, - summary: - "<p>The survivors plan their next steps; Cersei makes a power move.</p><p></p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1623966", - }, - }, - }, - { - id: 1623967, - url: - "http://www.tvmaze.com/episodes/1623967/game-of-thrones-8x05-the-bells", - name: "The Bells", - season: 8, - number: 5, - airdate: "2019-05-12", - airtime: "21:00", - airstamp: "2019-05-13T01:00:00+00:00", - runtime: 79, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/196/491994.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/196/491994.jpg", - }, - summary: - "<p>Varys betrays his queen, and Daenerys brings her forces to King's Landing.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1623967", - }, - }, - }, - { - id: 1623968, - url: - "http://www.tvmaze.com/episodes/1623968/game-of-thrones-8x06-the-iron-throne", - name: "The Iron Throne", - season: 8, - number: 6, - airdate: "2019-05-19", - airtime: "21:00", - airstamp: "2019-05-20T01:00:00+00:00", - runtime: 80, - image: { - medium: - "http://static.tvmaze.com/uploads/images/medium_landscape/198/495648.jpg", - original: - "http://static.tvmaze.com/uploads/images/original_untouched/198/495648.jpg", - }, - summary: - "<p>In the aftermath of the devastating attack on King's Landing, Daenerys must face the survivors.</p>", - _links: { - self: { - href: "http://api.tvmaze.com/episodes/1623968", - }, - }, - }, - ]; -} diff --git a/index.html b/index.html index 9a400d1..87b70ac 100644 --- a/index.html +++ b/index.html @@ -1,21 +1,21 @@ -<!DOCTYPE html> -<html lang="en"> - <head> - <meta charset="UTF-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>TV Show Project | My Name (My GitHub username) - - - - - -
-
- - - - - - - - + + + + + + + TV Show Project | Toluwalase Tiamiyu (TTiamiyu) + + + + + + +
+
+ + + + + + \ No newline at end of file diff --git a/levels/Reviewers-All-Requirements.md b/levels/Reviewers-All-Requirements.md index 36e72de..fa454e4 100644 --- a/levels/Reviewers-All-Requirements.md +++ b/levels/Reviewers-All-Requirements.md @@ -1,51 +1,51 @@ -There are the main requirements that a submitted project needs checked by reviewers. -Trainees should not need to refer to this document, and should focus on completing each level one at a time. - -1. It is deployed on GitHub pages or Netlify -1. The site must fetch data from an API at `TVMaze.com`, never a JSON file in the repo - 1. The page should state somewhere that the data has (originally) come from [TVMaze.com](https://tvmaze.com/), and link back to that site. - 1. During a visit to the website it should never fetch any URL more than once. (Check this using the dev tools network inspector) - 1. The site should indicate when data is loading. - 1. If an error occurred loading the data, notify the user on the page with a useful message (Not only in the console) -1. Listing Shows - When the site starts, present a listing of all shows ("shows listing") - 1. For each show, display at least: - 1. name - 1. image - 1. summary - 1. genres - 1. status - 1. rating - 1. runtime - 1. When a show name is clicked, it should: - 1. Fetch and present episodes from that show - 1. Hide the "shows listing" view - 1. Enable episode search / select (see below) - 1. Have a navigation link or button to enable the user to return to the "shows listing" - 1. When this is clicked, the episodes listing should be hidden - 1. Ensure that the search and selector controls still work correctly when you switch from shows listing to episodes listing and back -1. Listing Episodes - When a show is selected, all episodes must be on the page shown for that given show, with at least: - 1. The name of the episode - 1. The combined season number and episode number into a zero-padded episode code: `S02E07` is correct, `S2E7` is incorrect. - 1. The medium-sized image for the episode - 1. The summary text of the episode -1. Select Shows - a `select` element to your page so the user can choose a show. - 1. When the user first loads the page, use the fetched list of available shows, and add an entry to the drop-down per show. - 1. When a user selects a show, display the episodes for that show after fetching the episode list. - 1. The select must list shows in alphabetical order, case-insensitive. -1. Select Episodes - a `select` drop-down which lets the user jump quickly to a particular episode: - 1. The select options are updated whenever a new show is selected, and this select isn't used otherwise - 1. The select input should list all episodes in the format: "S01E01 - Episode Title" - 1. When the user makes a selection, they should be taken directly to that episode on the page -1. Search Shows - When a user types a search term into the search box: - 1. Only shows whose summary **OR** name contains the search term should be displayed - 1. The search should be case-**in**sensitive - 1. The display should update **immediately** after each keystroke changes the input - 1. Display how many shows match the current search - 1. If the search box is cleared, **all** shows should be shown -1. Search Episodes - When a user types a search term into the search box: - 1. Only episodes whose summary **OR** name contains the search term should be displayed - 1. The search should be case-**in**sensitive - 1. The display should update **immediately** after each keystroke changes the input - 1. Display how many episodes match the current search - 1. If the search box is cleared, **all** episodes should be shown - +There are the main requirements that a submitted project needs checked by reviewers. +Trainees should not need to refer to this document, and should focus on completing each level one at a time. + +1. It is deployed on GitHub pages or Netlify +1. The site must fetch data from an API at `TVMaze.com`, never a JSON file in the repo + 1. The page should state somewhere that the data has (originally) come from [TVMaze.com](https://tvmaze.com/), and link back to that site. + 1. During a visit to the website it should never fetch any URL more than once. (Check this using the dev tools network inspector) + 1. The site should indicate when data is loading. + 1. If an error occurred loading the data, notify the user on the page with a useful message (Not only in the console) +1. Listing Shows - When the site starts, present a listing of all shows ("shows listing") + 1. For each show, display at least: + 1. name + 1. image + 1. summary + 1. genres + 1. status + 1. rating + 1. runtime + 1. When a show name is clicked, it should: + 1. Fetch and present episodes from that show + 1. Hide the "shows listing" view + 1. Enable episode search / select (see below) + 1. Have a navigation link or button to enable the user to return to the "shows listing" + 1. When this is clicked, the episodes listing should be hidden + 1. Ensure that the search and selector controls still work correctly when you switch from shows listing to episodes listing and back +1. Listing Episodes - When a show is selected, all episodes must be on the page shown for that given show, with at least: + 1. The name of the episode + 1. The combined season number and episode number into a zero-padded episode code: `S02E07` is correct, `S2E7` is incorrect. + 1. The medium-sized image for the episode + 1. The summary text of the episode +1. Select Shows - a `select` element to your page so the user can choose a show. + 1. When the user first loads the page, use the fetched list of available shows, and add an entry to the drop-down per show. + 1. When a user selects a show, display the episodes for that show after fetching the episode list. + 1. The select must list shows in alphabetical order, case-insensitive. +1. Select Episodes - a `select` drop-down which lets the user jump quickly to a particular episode: + 1. The select options are updated whenever a new show is selected, and this select isn't used otherwise + 1. The select input should list all episodes in the format: "S01E01 - Episode Title" + 1. When the user makes a selection, they should be taken directly to that episode on the page +1. Search Shows - When a user types a search term into the search box: + 1. Only shows whose summary **OR** name contains the search term should be displayed + 1. The search should be case-**in**sensitive + 1. The display should update **immediately** after each keystroke changes the input + 1. Display how many shows match the current search + 1. If the search box is cleared, **all** shows should be shown +1. Search Episodes - When a user types a search term into the search box: + 1. Only episodes whose summary **OR** name contains the search term should be displayed + 1. The search should be case-**in**sensitive + 1. The display should update **immediately** after each keystroke changes the input + 1. Display how many episodes match the current search + 1. If the search box is cleared, **all** episodes should be shown + diff --git a/levels/level-0.md b/levels/level-0.md index 42e681e..acf9f46 100644 --- a/levels/level-0.md +++ b/levels/level-0.md @@ -1,41 +1,41 @@ -# Level 0 - -The goals of level 0 are to: -* Create a GitHub repository with the starter scaffolding in-place. -* Deploy it to **GitHub Pages**. -* Make sure whenever you push changes, your live site will be updated. - -## Fork your repository - -1. Go to https://github.com/CodeYourFuture/Project-TV-Show -2. Fork the repo to your account -3. Do not enable `Include all branches` - -## Deployment to GitHub Pages - -Follow the [CYF GitHub Pages Deployment Guide](https://curriculum.codeyourfuture.io/guides/deploying/ghpages/). - -> [!TIP] -> Deployment to **Netlify** is only required upon reaching **Level 500**. Using GitHub Pages until then helps conserve build credits during the development phase. - -## Get set up on your laptop - -1. Clone your repository. -2. Open your repository in VS Code. -3. Open the `index.html` page in Chrome. -4. Make sure in Chrome you can see the text "Got 73 episode(s)" in red. If you can't, something has gone wrong. -5. Edit `index.html` to include your name and GitHub username in the page title instead of "(My Name (My GitHub username))". - -## Push your changes - -1. Commit your changes to your `index.html` to your git repository (with a clear commit message). -2. Push your changes to your GitHub repository. -3. Check your GitHub Pages URL to ensure the changes are live. - -## Completion criteria - -You have completed level 0 when: -- [ ] You have forked the GitHub repository called `Project-TV-Show` into your account. -- [ ] The `index.html` page on your GitHub project contains your name and GitHub username. -- [ ] Your project is successfully deployed to **GitHub Pages**. +# Level 0 + +The goals of level 0 are to: +* Create a GitHub repository with the starter scaffolding in-place. +* Deploy it to **GitHub Pages**. +* Make sure whenever you push changes, your live site will be updated. + +## Fork your repository + +1. Go to https://github.com/CodeYourFuture/Project-TV-Show +2. Fork the repo to your account +3. Do not enable `Include all branches` + +## Deployment to GitHub Pages + +Follow the [CYF GitHub Pages Deployment Guide](https://curriculum.codeyourfuture.io/guides/deploying/ghpages/). + +> [!TIP] +> Deployment to **Netlify** is only required upon reaching **Level 500**. Using GitHub Pages until then helps conserve build credits during the development phase. + +## Get set up on your laptop + +1. Clone your repository. +2. Open your repository in VS Code. +3. Open the `index.html` page in Chrome. +4. Make sure in Chrome you can see the text "Got 73 episode(s)" in red. If you can't, something has gone wrong. +5. Edit `index.html` to include your name and GitHub username in the page title instead of "(My Name (My GitHub username))". + +## Push your changes + +1. Commit your changes to your `index.html` to your git repository (with a clear commit message). +2. Push your changes to your GitHub repository. +3. Check your GitHub Pages URL to ensure the changes are live. + +## Completion criteria + +You have completed level 0 when: +- [ ] You have forked the GitHub repository called `Project-TV-Show` into your account. +- [ ] The `index.html` page on your GitHub project contains your name and GitHub username. +- [ ] Your project is successfully deployed to **GitHub Pages**. - [ ] Your deployed project has your name and GitHub username in its title. \ No newline at end of file diff --git a/levels/level-100.md b/levels/level-100.md index a50ddce..4b368b8 100644 --- a/levels/level-100.md +++ b/levels/level-100.md @@ -1,25 +1,25 @@ -# Level 100 - -For level 100, we are going to display information about every episode of a single TV show. - -## Requirements - -1. All episodes must be shown -2. For each episode, _at least_ following must be displayed: - 1. The name of the episode - 2. The season number - 3. The episode number - 4. The medium-sized image for the episode - 5. The summary text of the episode -3. Combine season number and episode number into an **episode code**: - 1. Each part should be zero-padded to two digits. - 2. Example: `S02E07` would be the code for the 7th episode of the 2nd season. `S2E7` would be incorrect. -4. Your page should state somewhere that the data has (originally) come from [TVMaze.com](https://tvmaze.com/), and link back to that site (or the specific episode on that site). See [tvmaze.com/api#licensing](https://www.tvmaze.com/api#licensing). - -### Screenshot of minimal version - -Note: Provided your project meets the above requirements, it can **look** however you want. Do the simplest thing to begin with. - -Here is one example layout. - -![Screenshot of a website with cards showing per-episode data according to the requirements](example-screenshots/example-level-100.png) +# Level 100 + +For level 100, we are going to display information about every episode of a single TV show. + +## Requirements + +1. All episodes must be shown +2. For each episode, _at least_ following must be displayed: + 1. The name of the episode + 2. The season number + 3. The episode number + 4. The medium-sized image for the episode + 5. The summary text of the episode +3. Combine season number and episode number into an **episode code**: + 1. Each part should be zero-padded to two digits. + 2. Example: `S02E07` would be the code for the 7th episode of the 2nd season. `S2E7` would be incorrect. +4. Your page should state somewhere that the data has (originally) come from [TVMaze.com](https://tvmaze.com/), and link back to that site (or the specific episode on that site). See [tvmaze.com/api#licensing](https://www.tvmaze.com/api#licensing). + +### Screenshot of minimal version + +Note: Provided your project meets the above requirements, it can **look** however you want. Do the simplest thing to begin with. + +Here is one example layout. + +![Screenshot of a website with cards showing per-episode data according to the requirements](example-screenshots/example-level-100.png) diff --git a/levels/level-200.md b/levels/level-200.md index 89c28d3..32ab32e 100644 --- a/levels/level-200.md +++ b/levels/level-200.md @@ -1,86 +1,86 @@ -# Level 200 - -For level 200, you are not allowed to work on the same codebase as you worked on for level 100. - -Swap repos with a random person in your class. You may find it helpful to do this first step together: - -1. Go to _your_ copy of `Project-TV-Show` and click on the setting -2. Go to the "collaborators" section -3. Next "manage access", click "add people" -4. Type the username your partner -5. Click the green add button -6. Visit the URL for your _partner's_ project and accept the invitation to collaborate / check your email for the invite link -7. Clone your _partner's_ repository to your laptop, you will need to give it a different name, such as `Project-TV-Show-THEIR_NAME` - -Now, work individually to complete level 200: - -Look at their level 100 implementation. - -Compare their implementation to yours. Think: -1. How is it different? -2. What do you prefer about your implementation? -3. What do you prefer about their implementation? -4. What did you learn that you didn't know before? - -They should do the same with your repository. - -Have a discussion about your answers to these questions. In class, together you should give talk for 5 minutes about your conclusions. (Do this in small groups - we don't want to take all day). - -## Refactoring - -**Before implementing new features**, take some time to change the codebase you're going to build level 200 in. Change anything you think will make it easier to add more features. - -Some example ideas that you may want to think about: -1. Could any variables or functions have more clear names, to help you understand what they do? -2. Would [extracting functions](https://code.visualstudio.com/docs/editor/refactoring) help make some code easier to understand? - -Work in a new branch on your _partner's_ repo, making any changes you think are useful. -Then make a pull request to your _partner's_ main branch (take care not to PR to the CYF main branch yet). -Have them review, and when happy, merge your PR. - -![Git branch diagram for level200](branch-level200.png) - -![Select the partner repo in the dropdown when making a PR for level200](pr-level200.png) - - -## Adding new functionality - -Level 200 is all about being able to filter episodes. - -### Search - -Add a live search input which meets the following requirements: - -When a user types a search term into the search box: -1. Only episodes whose summary **OR** name contains the search term should be displayed -2. The search should be case-**in**sensitive -3. The display should update **immediately** after each keystroke changes the input -4. Display how many episodes match the current search -5. If the search box is cleared, **all** episodes should be shown - -Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. - -#### Screenshot of minimal version - -Note: Provided your project meets the above requirements, it can **look** however you want. - -Here is one example layout. - -![Screenshot of a website with a search term entered in the search box, and only matching episodes shown](example-screenshots/example-level-200-search.jpg) - -### Episode selector - -Add a `select` drop-down which lets the user jump quickly to a particular episode, with the following requirements: -1. The select input should list all episodes in the format: "S01E01 - Winter is Coming" -2. When the user makes a selection, they should be taken directly to that episode in the list -3. Bonus: if you prefer, when the select is used, ONLY show the selected episode. If you do this, be sure to provide a way for the user to see all episodes again. - -Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. - -#### Screenshot of minimal version - -Note: Provided your project meets the above requirements, it can **look** however you want. - -Here is one example layout. - -![Screenshot of a website with a drop-down listing all available episodes](example-screenshots/example-level-200-selector.jpg) +# Level 200 + +For level 200, you are not allowed to work on the same codebase as you worked on for level 100. + +Swap repos with a random person in your class. You may find it helpful to do this first step together: + +1. Go to _your_ copy of `Project-TV-Show` and click on the setting +2. Go to the "collaborators" section +3. Next "manage access", click "add people" +4. Type the username your partner +5. Click the green add button +6. Visit the URL for your _partner's_ project and accept the invitation to collaborate / check your email for the invite link +7. Clone your _partner's_ repository to your laptop, you will need to give it a different name, such as `Project-TV-Show-THEIR_NAME` + +Now, work individually to complete level 200: + +Look at their level 100 implementation. + +Compare their implementation to yours. Think: +1. How is it different? +2. What do you prefer about your implementation? +3. What do you prefer about their implementation? +4. What did you learn that you didn't know before? + +They should do the same with your repository. + +Have a discussion about your answers to these questions. In class, together you should give talk for 5 minutes about your conclusions. (Do this in small groups - we don't want to take all day). + +## Refactoring + +**Before implementing new features**, take some time to change the codebase you're going to build level 200 in. Change anything you think will make it easier to add more features. + +Some example ideas that you may want to think about: +1. Could any variables or functions have more clear names, to help you understand what they do? +2. Would [extracting functions](https://code.visualstudio.com/docs/editor/refactoring) help make some code easier to understand? + +Work in a new branch on your _partner's_ repo, making any changes you think are useful. +Then make a pull request to your _partner's_ main branch (take care not to PR to the CYF main branch yet). +Have them review, and when happy, merge your PR. + +![Git branch diagram for level200](branch-level200.png) + +![Select the partner repo in the dropdown when making a PR for level200](pr-level200.png) + + +## Adding new functionality + +Level 200 is all about being able to filter episodes. + +### Search + +Add a live search input which meets the following requirements: + +When a user types a search term into the search box: +1. Only episodes whose summary **OR** name contains the search term should be displayed +2. The search should be case-**in**sensitive +3. The display should update **immediately** after each keystroke changes the input +4. Display how many episodes match the current search +5. If the search box is cleared, **all** episodes should be shown + +Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. + +#### Screenshot of minimal version + +Note: Provided your project meets the above requirements, it can **look** however you want. + +Here is one example layout. + +![Screenshot of a website with a search term entered in the search box, and only matching episodes shown](example-screenshots/example-level-200-search.jpg) + +### Episode selector + +Add a `select` drop-down which lets the user jump quickly to a particular episode, with the following requirements: +1. The select input should list all episodes in the format: "S01E01 - Winter is Coming" +2. When the user makes a selection, they should be taken directly to that episode in the list +3. Bonus: if you prefer, when the select is used, ONLY show the selected episode. If you do this, be sure to provide a way for the user to see all episodes again. + +Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. + +#### Screenshot of minimal version + +Note: Provided your project meets the above requirements, it can **look** however you want. + +Here is one example layout. + +![Screenshot of a website with a drop-down listing all available episodes](example-screenshots/example-level-200-selector.jpg) diff --git a/levels/level-300.md b/levels/level-300.md index 9e0d9e4..437f1b8 100644 --- a/levels/level-300.md +++ b/levels/level-300.md @@ -1,39 +1,39 @@ -# Level 300 - -For level 300, you should switch back to your original codebase. - -You should have reviewed and merged your partner's level 200 changes through a PR to your own repo. - -Remember to pull the latest changes onto your local machine. - -Once again, compare their implementation to yours. Think: -1. How is it different? -2. What do you prefer about your implementation? -3. What do you prefer about their implementation? -4. What did you learn that you didn't know before? - -Have a discussion about your answers to these questions. In class, together, give a 3 minute talk about your conclusions. - -## Refactoring - -Like with level 200, feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. - -Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. - -## Adding new functionality - -Level 300 is about getting rid of our static data from `episodes.js`, and instead using an API. - -### Requirements - -1. You must delete the `episodes.js` file from your repository. -2. Your website must still work the same, but by using a `fetch` request to https://api.tvmaze.com/shows/82/episodes. This URL should serve the exact same content as was returned by `getAllEpisodes` in `episodes.js`. -3. You must fetch this URL only _once_ per visit to your website. You should not re-fetch when someone searches, scrolls, or selects an episode from the drop-down. -4. If you don't have data yet, you should show something to tell the user to wait for the data. -5. If an error occurred loading the data, notify the user. - 1. Note: real users don't look in the console - `console.log` or `console.error` are not sufficient for this requirement. - 2. You will need to simulate an error to test this out yourself. - -### Documentation - -You can see that this endpoint has been documented here: https://www.tvmaze.com/api#show-episode-list +# Level 300 + +For level 300, you should switch back to your original codebase. + +You should have reviewed and merged your partner's level 200 changes through a PR to your own repo. + +Remember to pull the latest changes onto your local machine. + +Once again, compare their implementation to yours. Think: +1. How is it different? +2. What do you prefer about your implementation? +3. What do you prefer about their implementation? +4. What did you learn that you didn't know before? + +Have a discussion about your answers to these questions. In class, together, give a 3 minute talk about your conclusions. + +## Refactoring + +Like with level 200, feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. + +Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. + +## Adding new functionality + +Level 300 is about getting rid of our static data from `episodes.js`, and instead using an API. + +### Requirements + +1. You must delete the `episodes.js` file from your repository. +2. Your website must still work the same, but by using a `fetch` request to https://api.tvmaze.com/shows/82/episodes. This URL should serve the exact same content as was returned by `getAllEpisodes` in `episodes.js`. +3. You must fetch this URL only _once_ per visit to your website. You should not re-fetch when someone searches, scrolls, or selects an episode from the drop-down. +4. If you don't have data yet, you should show something to tell the user to wait for the data. +5. If an error occurred loading the data, notify the user. + 1. Note: real users don't look in the console - `console.log` or `console.error` are not sufficient for this requirement. + 2. You will need to simulate an error to test this out yourself. + +### Documentation + +You can see that this endpoint has been documented here: https://www.tvmaze.com/api#show-episode-list diff --git a/levels/level-400.md b/levels/level-400.md index 60ddc9e..943d686 100644 --- a/levels/level-400.md +++ b/levels/level-400.md @@ -1,61 +1,61 @@ -# Level 400 - -For level 400, you should work in the repo of your partner from level 200. - -You do not need to re-add yourself as a collaborator. - -Remember to change to the right directory on your machine, and pull the latest changes from their main branch. - -Before writing any new code, look at their level 300 implementation. - -Compare their implementation to yours. Think: -1. How is it different? -2. What do you prefer about your implementation? -3. What do you prefer about their implementation? -4. What did you learn that you didn't know before? - -They should do the same with your repository. - -Have a discussion about your answers to these questions. In class, together you should give a 3 minute talk about your conclusions. - -## Refactoring - -Feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. - -Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. - -## Adding new functionality - -Level 400 is about expanding beyond one TV show. - -Until now, your site has only showed information about the episode of one TV show. - -But TVmaze has information about lots of TV shows, all in the same format. - -We want to display any of them. - -### Requirements - -1. Add a `select` element to your page so the user can choose a show. -2. When the user first loads the page, make a `fetch` request to https://api.tvmaze.com/shows ([documentation](https://www.tvmaze.com/api#show-index)) to get a list of available shows, and add an entry to the drop-down per show. -3. When a user selects a show, display the episodes for that show, just like the earlier levels of this project. - - You will need to perform a `fetch` to get the episode list. -4. Make sure that your search and episode selector controls still work correctly when you change shows. -5. Your select must list shows in alphabetical order, case-insensitive. -6. During one user's visit to your website, you should never fetch any URL more than once. - -> [!NOTE] -> Be _careful_ when developing with fetch. By default, every time you make a small change to your app it will be restarted by live server - if you are fetching JSON on page load, the JSON will be downloaded again and again. These frequent HTTP requests may lead to the API permanently banning your IP address from further requests, or "throttling" it for some time. Worse, if they don't, they may cause performance issues for the API service we are using. - -Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. - -#### Screenshot of minimal version - -Note: Provided your project meets the above requirements, it can **look** however you want. - -Here is one example layout. - -![Screenshot of a website with a drop-down list with the show "Breaking Bad" selected](example-screenshots/example-level-400-1.jpg) - -![Screenshot of a website with a drop-down list showing multiple TV shows](example-screenshots/example-level-400-1.jpg) +# Level 400 + +For level 400, you should work in the repo of your partner from level 200. + +You do not need to re-add yourself as a collaborator. + +Remember to change to the right directory on your machine, and pull the latest changes from their main branch. + +Before writing any new code, look at their level 300 implementation. + +Compare their implementation to yours. Think: +1. How is it different? +2. What do you prefer about your implementation? +3. What do you prefer about their implementation? +4. What did you learn that you didn't know before? + +They should do the same with your repository. + +Have a discussion about your answers to these questions. In class, together you should give a 3 minute talk about your conclusions. + +## Refactoring + +Feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. + +Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. + +## Adding new functionality + +Level 400 is about expanding beyond one TV show. + +Until now, your site has only showed information about the episode of one TV show. + +But TVmaze has information about lots of TV shows, all in the same format. + +We want to display any of them. + +### Requirements + +1. Add a `select` element to your page so the user can choose a show. +2. When the user first loads the page, make a `fetch` request to https://api.tvmaze.com/shows ([documentation](https://www.tvmaze.com/api#show-index)) to get a list of available shows, and add an entry to the drop-down per show. +3. When a user selects a show, display the episodes for that show, just like the earlier levels of this project. + + You will need to perform a `fetch` to get the episode list. +4. Make sure that your search and episode selector controls still work correctly when you change shows. +5. Your select must list shows in alphabetical order, case-insensitive. +6. During one user's visit to your website, you should never fetch any URL more than once. + +> [!NOTE] +> Be _careful_ when developing with fetch. By default, every time you make a small change to your app it will be restarted by live server - if you are fetching JSON on page load, the JSON will be downloaded again and again. These frequent HTTP requests may lead to the API permanently banning your IP address from further requests, or "throttling" it for some time. Worse, if they don't, they may cause performance issues for the API service we are using. + +Send a pull request to your partner's repo with this functionality. Have them review, and when happy, merge your PR. + +#### Screenshot of minimal version + +Note: Provided your project meets the above requirements, it can **look** however you want. + +Here is one example layout. + +![Screenshot of a website with a drop-down list with the show "Breaking Bad" selected](example-screenshots/example-level-400-1.jpg) + +![Screenshot of a website with a drop-down list showing multiple TV shows](example-screenshots/example-level-400-1.jpg) diff --git a/levels/level-500.md b/levels/level-500.md index 0c0e4f2..c3eadda 100644 --- a/levels/level-500.md +++ b/levels/level-500.md @@ -1,71 +1,71 @@ -# Level 500 - -For level 500, you should switch back to your original codebase. - -You should have reviewed and merged someone else's level 400 implementation. - -Once again, compare their implementation to yours. Think: - -1. How is it different? -2. What do you prefer about your implementation? -3. What do you prefer about their implementation? -4. What did you learn that you didn't know before? - -Have a discussion about your answers to these questions. In class, together you should give a 3 minute talk about your conclusions. - ---- - -### Technical Workflow - -**Best Practice: Use Feature Branches** -To maintain a clean workflow, follow these steps for Level 500: -* Once you have merged Level 400 and are satisfied with the changes, **create a new branch** (e.g., `feature/level-500`) to continue your development. -* After completing all Level 500 requirements on this branch, merge it into your main branch. -* **Important:** Test your changes thoroughly on GitHub Pages before moving to the final deployment. - ---- - -## Refactoring - -Feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. - -Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. - ---- - -## Adding new functionality - -Level 500 is about adding a front-page which lets users select (and find) shows from your shows list. - -### Requirements - -1. When your app starts, present a listing of all shows ("shows listing") - 1. For each show, you must display at least the name, image, summary, genres, status, rating, and runtime. -2. When a show name is clicked, your app should: - 1. Fetch and present episodes from that show (enabling episode search and selection as before) - 2. Hide the "shows listing" view -3. Add a navigation link to enable the user to return to the "shows listing" - 1. When this is clicked, the episodes listing should be hidden -4. Provide a free-text show search through show names, genres, and summary texts -5. Ensure that your episode search and episode selector controls still work correctly when you switch from shows listing to the episodes listing and back -6. During one user's visit to your website, you should never fetch any URL more than once. - -#### Screenshot of minimal version - -Note: Provided your project meets the above requirements, it can **look** however you want. - -Here is one example layout. - -![Screenshot of a website with a drop-down list with the show "Breaking Bad" selected](example-screenshots/example-level-500.jpg) - -### Deployment to Netlify - -To complete the project, we will move from GitHub Pages to **Netlify** to practice using a more advanced hosting platform. - -Follow the [Official CYF Netlify Deployment Guide](https://curriculum.codeyourfuture.io/guides/deployment-netlify/) for your project. - -## Submission - -Once you have finished your level 500 it is ready to submit. - -Check the [README.md](../README.md) for this repo for instructions. +# Level 500 + +For level 500, you should switch back to your original codebase. + +You should have reviewed and merged someone else's level 400 implementation. + +Once again, compare their implementation to yours. Think: + +1. How is it different? +2. What do you prefer about your implementation? +3. What do you prefer about their implementation? +4. What did you learn that you didn't know before? + +Have a discussion about your answers to these questions. In class, together you should give a 3 minute talk about your conclusions. + +--- + +### Technical Workflow + +**Best Practice: Use Feature Branches** +To maintain a clean workflow, follow these steps for Level 500: +* Once you have merged Level 400 and are satisfied with the changes, **create a new branch** (e.g., `feature/level-500`) to continue your development. +* After completing all Level 500 requirements on this branch, merge it into your main branch. +* **Important:** Test your changes thoroughly on GitHub Pages before moving to the final deployment. + +--- + +## Refactoring + +Feel free to change anything in your codebase which you think will make it easier to work with, or to build new features. + +Make a branch and pull request for yourself, and then have your partner review, making sure they understand the changes made. + +--- + +## Adding new functionality + +Level 500 is about adding a front-page which lets users select (and find) shows from your shows list. + +### Requirements + +1. When your app starts, present a listing of all shows ("shows listing") + 1. For each show, you must display at least the name, image, summary, genres, status, rating, and runtime. +2. When a show name is clicked, your app should: + 1. Fetch and present episodes from that show (enabling episode search and selection as before) + 2. Hide the "shows listing" view +3. Add a navigation link to enable the user to return to the "shows listing" + 1. When this is clicked, the episodes listing should be hidden +4. Provide a free-text show search through show names, genres, and summary texts +5. Ensure that your episode search and episode selector controls still work correctly when you switch from shows listing to the episodes listing and back +6. During one user's visit to your website, you should never fetch any URL more than once. + +#### Screenshot of minimal version + +Note: Provided your project meets the above requirements, it can **look** however you want. + +Here is one example layout. + +![Screenshot of a website with a drop-down list with the show "Breaking Bad" selected](example-screenshots/example-level-500.jpg) + +### Deployment to Netlify + +To complete the project, we will move from GitHub Pages to **Netlify** to practice using a more advanced hosting platform. + +Follow the [Official CYF Netlify Deployment Guide](https://curriculum.codeyourfuture.io/guides/deployment-netlify/) for your project. + +## Submission + +Once you have finished your level 500 it is ready to submit. + +Check the [README.md](../README.md) for this repo for instructions. diff --git a/levels/level-999.md b/levels/level-999.md index cf3d894..e3a3509 100644 --- a/levels/level-999.md +++ b/levels/level-999.md @@ -1,22 +1,22 @@ -# Extra options - -Do not do any of these until you have completed level 500! - -Submit your Pull Request for level 500 first, and then work on these in a new branch for level 999. - -Here are some ideas for consideration for further work: -1. Add cast listing to your show listing, http://api.tvmaze.com/shows/1?embed=cast -2. Add cast listing to your episode listing, http://api.tvmaze.com/shows/1?embed=cast -3. Allow clicking a cast member to present a view of all shows the person has appeared in http://api.tvmaze.com/people/1/castcredits - - Linking those back into your episodes view of each show. -4. Truncate long summaries and provide a "... read more..." control to reveal more. -5. Allow the user to choose to have the show list sorted by rating (highest rated shows first) -6. Have your search support start-of-word search, or other search types. -7. Make the browser's back and forward buttons navigate through your changed views (see [History.pushState()](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)). -8. Allow user to mark "favourite" shows -9. Allow user to store notes on each episode -10. Use local storage to cache the above, and perhaps also to cache episode lists -11. Paginate through results with a "load more" button - don't load 100s of episodes at a time. -12. Experiment with infinite scroll -13. Responsive design -14. Style your page to fit the theme of the show (colours, typography, background images, etc). Commit to one show to do this. +# Extra options + +Do not do any of these until you have completed level 500! + +Submit your Pull Request for level 500 first, and then work on these in a new branch for level 999. + +Here are some ideas for consideration for further work: +1. Add cast listing to your show listing, http://api.tvmaze.com/shows/1?embed=cast +2. Add cast listing to your episode listing, http://api.tvmaze.com/shows/1?embed=cast +3. Allow clicking a cast member to present a view of all shows the person has appeared in http://api.tvmaze.com/people/1/castcredits + - Linking those back into your episodes view of each show. +4. Truncate long summaries and provide a "... read more..." control to reveal more. +5. Allow the user to choose to have the show list sorted by rating (highest rated shows first) +6. Have your search support start-of-word search, or other search types. +7. Make the browser's back and forward buttons navigate through your changed views (see [History.pushState()](https://developer.mozilla.org/en-US/docs/Web/API/History/pushState)). +8. Allow user to mark "favourite" shows +9. Allow user to store notes on each episode +10. Use local storage to cache the above, and perhaps also to cache episode lists +11. Paginate through results with a "load more" button - don't load 100s of episodes at a time. +12. Experiment with infinite scroll +13. Responsive design +14. Style your page to fit the theme of the show (colours, typography, background images, etc). Commit to one show to do this. diff --git a/script.js b/script.js index 87a7de8..e74a694 100644 --- a/script.js +++ b/script.js @@ -1,12 +1,398 @@ -//You can edit ALL of the code here -function setup() { - const allEpisodes = getAllEpisodes(); - makePageForEpisodes(allEpisodes); -} - -function makePageForEpisodes(episodeList) { - const rootElem = document.getElementById("root"); - rootElem.textContent = `Got ${episodeList.length} episode(s)`; -} - -window.onload = setup; +let allEpisodes = []; +let allShows = []; +const cache = {}; // Rule 6: In-memory cache to prevent duplicate fetches +let currentView = "shows"; // State flag: "shows" or "episodes" + +async function setup() { + addTvmazeAttribution(); + showLoading("Loading shows, please wait..."); + + try { + // 1. Fetch all shows on page load (cached) + allShows = await fetchWithCache("https://api.tvmaze.com/shows"); + + // Rule 5: Sort shows alphabetically, case-insensitive + allShows.sort((a, b) => + a.name.localeCompare(b.name, undefined, { sensitivity: "base" }), + ); + + createControls(); + renderShowsListing(allShows); + } catch (error) { + showError("Failed to load TV shows. Please try again later."); + } +} + +// Helper function to handle cached fetches (Rule 6) +async function fetchWithCache(url) { + if (cache[url]) { + return cache[url]; + } + + const response = await fetch(url); + if (!response.ok) { + throw new Error(`HTTP error status: ${response.status}`); + } + + const data = await response.json(); + cache[url] = data; + return data; +} + +// Fetch and load episodes for a selected show ID +async function loadEpisodesForShow(showId) { + showLoading("Loading episodes, please wait..."); + + try { + const url = `https://api.tvmaze.com/shows/${showId}/episodes`; + allEpisodes = await fetchWithCache(url); + + currentView = "episodes"; + updateViewControls(); + + const showSelect = document.getElementById("show-select"); + if (showSelect) showSelect.value = showId; + + populateEpisodeSelect(allEpisodes); + const searchInput = document.getElementById("search-input"); + if (searchInput) searchInput.value = ""; + + makePageForEpisodes(allEpisodes); + } catch (error) { + showError("Failed to load episode data. Please try again later."); + } +} + +function showLoading(message = "Loading, please wait...") { + const rootElem = document.getElementById("root"); + rootElem.innerHTML = ` +
+
+

${message}

+
+ `; +} + +function showError(message) { + const rootElem = document.getElementById("root"); + rootElem.innerHTML = ` +
+

Something went wrong

+

${message}

+
+ `; +} + +function createControls() { + if (document.querySelector(".controls-container")) return; + + const controlsContainer = document.createElement("nav"); + controlsContainer.className = "controls-container"; + controlsContainer.setAttribute("aria-label", "Search and view controls"); + + // Navigation Back Link + const backBtn = document.createElement("button"); + backBtn.id = "back-to-shows-btn"; + backBtn.className = "nav-btn hidden"; + backBtn.textContent = "◄ Back to Shows"; + backBtn.addEventListener("click", () => { + currentView = "shows"; + const searchInput = document.getElementById("search-input"); + if (searchInput) searchInput.value = ""; + const showSelect = document.getElementById("show-select"); + if (showSelect) showSelect.value = ""; + updateViewControls(); + renderShowsListing(allShows); + }); + + // 1. Show Select Dropdown + const showSelect = document.createElement("select"); + showSelect.id = "show-select"; + showSelect.setAttribute("aria-label", "Select a TV Show"); + + const defaultShowOption = document.createElement("option"); + defaultShowOption.value = ""; + defaultShowOption.textContent = "Select a Show..."; + showSelect.appendChild(defaultShowOption); + + allShows.forEach((show) => { + const option = document.createElement("option"); + option.value = show.id; + option.textContent = show.name; + showSelect.appendChild(option); + }); + + // 2. Episode Select Dropdown + const episodeSelect = document.createElement("select"); + episodeSelect.id = "episode-select"; + episodeSelect.setAttribute("aria-label", "Select an Episode"); + + // 3. Search Input + const searchInput = document.createElement("input"); + searchInput.type = "text"; + searchInput.id = "search-input"; + searchInput.placeholder = "Search shows..."; + searchInput.setAttribute("aria-label", "Search shows or episodes"); + + // 4. Count Display + const countDisplay = document.createElement("span"); + countDisplay.id = "search-count"; + countDisplay.setAttribute("aria-live", "polite"); + + controlsContainer.appendChild(backBtn); + controlsContainer.appendChild(showSelect); + controlsContainer.appendChild(episodeSelect); + controlsContainer.appendChild(searchInput); + controlsContainer.appendChild(countDisplay); + + const rootElem = document.getElementById("root"); + rootElem.parentNode.insertBefore(controlsContainer, rootElem); + + // Event Listeners + showSelect.addEventListener("change", handleShowChange); + episodeSelect.addEventListener("change", handleSelect); + searchInput.addEventListener("input", handleSearch); +} + +function updateViewControls() { + const backBtn = document.getElementById("back-to-shows-btn"); + const episodeSelect = document.getElementById("episode-select"); + const searchInput = document.getElementById("search-input"); + + if (currentView === "shows") { + if (backBtn) backBtn.classList.add("hidden"); + if (episodeSelect) episodeSelect.classList.add("hidden"); + if (searchInput) + searchInput.placeholder = "Search shows (name, genre, summary)..."; + } else { + if (backBtn) backBtn.classList.remove("hidden"); + if (episodeSelect) episodeSelect.classList.remove("hidden"); + if (searchInput) searchInput.placeholder = "Search episodes..."; + } +} + +// Render Shows Page (2 Columns Grid) +function renderShowsListing(showsList) { + currentView = "shows"; + updateViewControls(); + + const rootElem = document.getElementById("root"); + rootElem.innerHTML = ""; + + if (showsList.length === 0) { + rootElem.innerHTML = "

No shows found matching your search criteria.

"; + updateSearchCount(0, allShows.length, "shows"); + return; + } + + const container = document.createElement("div"); + container.className = "shows-container"; + + showsList.forEach((show) => { + const card = document.createElement("article"); + card.className = "show-card"; + + // Header Title + const title = document.createElement("h2"); + title.textContent = show.name; + title.addEventListener("click", () => loadEpisodesForShow(show.id)); + + // Body Container (Image + Summary) + const bodyDiv = document.createElement("div"); + bodyDiv.className = "show-card-body"; + + // Media / Image Section + const mediaDiv = document.createElement("div"); + mediaDiv.className = "show-card-media"; + if (show.image && show.image.medium) { + const img = document.createElement("img"); + img.src = show.image.medium; + img.alt = show.name; + mediaDiv.appendChild(img); + } + mediaDiv.addEventListener("click", () => loadEpisodesForShow(show.id)); + + // Summary Section + const contentDiv = document.createElement("div"); + contentDiv.className = "show-card-content"; + const summary = document.createElement("div"); + summary.className = "show-card-summary"; + summary.innerHTML = show.summary || "

No summary available.

"; + contentDiv.appendChild(summary); + + bodyDiv.appendChild(mediaDiv); + bodyDiv.appendChild(contentDiv); + + // Footer Metadata Section + const metaDiv = document.createElement("div"); + metaDiv.className = "show-card-meta"; + metaDiv.innerHTML = ` +

Rated: ${show.rating && show.rating.average ? show.rating.average : "N/A"}

+

Genres: ${show.genres && show.genres.length > 0 ? show.genres.join(", ") : "N/A"}

+

Status: ${show.status || "N/A"}

+

Runtime: ${show.runtime ? show.runtime + " min" : "N/A"}

+ `; + + card.appendChild(title); + card.appendChild(bodyDiv); + card.appendChild(metaDiv); + + container.appendChild(card); + }); + + rootElem.appendChild(container); + updateSearchCount(showsList.length, allShows.length, "shows"); +} + +async function handleShowChange(event) { + const showId = event.target.value; + if (showId) { + await loadEpisodesForShow(showId); + } else { + renderShowsListing(allShows); + } +} + +function populateEpisodeSelect(episodes) { + const episodeSelect = document.getElementById("episode-select"); + if (!episodeSelect) return; + + episodeSelect.innerHTML = ""; + + const defaultOption = document.createElement("option"); + defaultOption.value = "ALL"; + defaultOption.textContent = "All Episodes"; + episodeSelect.appendChild(defaultOption); + + episodes.forEach((episode) => { + const option = document.createElement("option"); + option.value = episode.id; + const code = formatEpisodeCode(episode.season, episode.number); + option.textContent = `${code} - ${episode.name}`; + episodeSelect.appendChild(option); + }); +} + +function handleSelect(event) { + const selectedId = event.target.value; + const searchInput = document.getElementById("search-input"); + + if (searchInput) searchInput.value = ""; + + if (selectedId === "ALL") { + makePageForEpisodes(allEpisodes); + } else { + const selectedEpisode = allEpisodes.filter( + (episode) => String(episode.id) === String(selectedId), + ); + makePageForEpisodes(selectedEpisode); + } +} + +function handleSearch(event) { + const searchTerm = event.target.value.toLowerCase().trim(); + + if (currentView === "shows") { + const filteredShows = allShows.filter((show) => { + const nameMatch = show.name.toLowerCase().includes(searchTerm); + const summaryMatch = (show.summary || "") + .toLowerCase() + .includes(searchTerm); + const genreMatch = show.genres + ? show.genres.some((g) => g.toLowerCase().includes(searchTerm)) + : false; + + return nameMatch || summaryMatch || genreMatch; + }); + + renderShowsListing(filteredShows); + } else { + const episodeSelect = document.getElementById("episode-select"); + if (episodeSelect) episodeSelect.value = "ALL"; + + const filteredEpisodes = allEpisodes.filter((episode) => { + const nameMatches = episode.name.toLowerCase().includes(searchTerm); + const summaryMatches = (episode.summary || "") + .toLowerCase() + .includes(searchTerm); + + return nameMatches || summaryMatches; + }); + + makePageForEpisodes(filteredEpisodes); + } +} + +function updateSearchCount(matchCount, totalCount, type = "episodes") { + const countDisplay = document.getElementById("search-count"); + if (countDisplay) { + countDisplay.textContent = `Displaying ${matchCount}/${totalCount} ${type}`; + } +} + +function formatEpisodeCode(season, number) { + const paddedSeason = String(season).padStart(2, "0"); + const paddedNumber = String(number).padStart(2, "0"); + return `S${paddedSeason}E${paddedNumber}`; +} + +// Render Episodes Page +function makePageForEpisodes(episodeList) { + const rootElem = document.getElementById("root"); + rootElem.innerHTML = ""; + + if (episodeList.length === 0) { + rootElem.innerHTML = "

No episodes found matching your criteria.

"; + updateSearchCount(0, allEpisodes.length, "episodes"); + return; + } + + const container = document.createElement("div"); + container.className = "episodes-container"; + + episodeList.forEach((episode) => { + const card = document.createElement("article"); + card.className = "episode-card"; + + // Card Header + const header = document.createElement("div"); + header.className = "episode-header"; + const title = document.createElement("h3"); + const code = formatEpisodeCode(episode.season, episode.number); + title.textContent = `${episode.name} - ${code}`; + header.appendChild(title); + card.appendChild(header); + + // Episode Image + if (episode.image && episode.image.medium) { + const img = document.createElement("img"); + img.src = episode.image.medium; + img.alt = episode.name; + card.appendChild(img); + } + + // Episode Summary + const summary = document.createElement("div"); + summary.className = "episode-summary"; + summary.innerHTML = episode.summary || "

No summary available.

"; + card.appendChild(summary); + + container.appendChild(card); + }); + + rootElem.appendChild(container); + updateSearchCount(episodeList.length, allEpisodes.length, "episodes"); +} + +function addTvmazeAttribution() { + if (document.getElementById("tvmaze-attribution")) return; + + const footer = document.createElement("footer"); + footer.id = "tvmaze-attribution"; + footer.innerHTML = ` +

Data provided by TVMaze.com

+ `; + document.body.appendChild(footer); +} + +window.onload = setup; diff --git a/style.css b/style.css index 77cb8d4..2f51895 100644 --- a/style.css +++ b/style.css @@ -1,3 +1,315 @@ -#root { - color: red; -} +/* General Layout & Fonts */ +* { + box-sizing: border-box; +} + +body { + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, + sans-serif; + margin: 0; + padding: 0; + background-color: #000000; /* True black background */ + color: #f8fafc; /* High contrast white/slate for maximum legibility */ +} + +.hidden { + display: none !important; +} + +/* Controls Container Styling */ +.controls-container { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 12px; + background-color: #121214; /* Deep dark surface */ + border-bottom: 1px solid #27272a; + padding: 16px 24px; + position: sticky; + top: 0; + z-index: 100; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); +} + +.controls-container select, +.controls-container input[type="text"] { + padding: 10px 14px; + background-color: #18181b; + color: #ffffff; + border: 1px solid #3f3f46; + border-radius: 6px; + font-size: 1rem; + outline: none; +} + +.controls-container select:focus, +.controls-container input[type="text"]:focus { + border-color: #38bdf8; + outline: 3px solid #38bdf8; + outline-offset: 1px; +} + +.controls-container select { + max-width: 220px; +} + +.controls-container input[type="text"] { + flex: 1; + min-width: 200px; +} + +.nav-btn { + padding: 10px 18px; + background-color: #1e293b; + color: #f8fafc; + border: 2px solid #38bdf8; + border-radius: 6px; + cursor: pointer; + font-weight: 600; + transition: + background-color 0.2s ease, + transform 0.15s ease; +} + +.nav-btn:hover, +.nav-btn:focus { + background-color: #2563eb; + color: #ffffff; + outline: 3px solid #ffffff; + outline-offset: 2px; +} + +#search-count { + color: #cbd5e1; + font-weight: 600; + font-size: 0.95rem; + margin-left: auto; +} + +/* Loading & Error States */ +.loading-container, +.error-container { + text-align: center; + padding: 60px 20px; + color: #f8fafc; +} + +.spinner { + width: 40px; + height: 40px; + margin: 0 auto 16px; + border: 4px solid #27272a; + border-top: 4px solid #38bdf8; + border-radius: 50%; + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } +} + +/* Main Container Layouts */ +#root { + max-width: 1200px; + margin: 24px auto; + padding: 0 16px; +} + +/* Shows Listing Layout - 2 Side by Side */ +/* Shows Listing Layout - 3 Side by Side */ +.shows-container { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 20px; +} + +/* Updated Responsive Breakpoints for 3-Column Layout */ +@media (max-width: 1024px) { + .shows-container { + grid-template-columns: repeat(2, 1fr); + } +} + +@media (max-width: 680px) { + .shows-container { + grid-template-columns: 1fr; + } +} + +.show-card { + display: flex; + flex-direction: column; + gap: 16px; + background-color: #121214; /* Deep dark container card */ + border: 2px solid #27272a; + border-radius: 10px; + padding: 20px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6); + transition: + transform 0.15s ease, + border-color 0.15s ease, + box-shadow 0.15s ease; +} + +/* Enhanced focus state for TV remote D-pad navigation */ +.show-card:hover, +.show-card:focus-within { + transform: scale(1.02); + border-color: #38bdf8; + box-shadow: + 0 0 0 4px rgba(56, 189, 248, 0.3), + 0 8px 24px rgba(0, 0, 0, 0.8); +} + +.show-card-body { + flex-direction: column; /* Stacks image on top of text inside narrow cards */ + align-items: center; +} + +.show-card-media { + width: 100%; + max-width: 180px; /* Centers the poster neatly */ +} + +.show-card-media img { + width: 100%; + border-radius: 6px; + object-fit: cover; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5); +} + +.show-card-content { + flex: 1; +} + +.show-card-content h2 { + margin: 0 0 8px 0; + font-size: 1.3rem; + color: #38bdf8; /* Vibrant accessible accent color on black */ + cursor: pointer; +} + +.show-card-content h2:hover, +.show-card-content h2:focus { + text-decoration: underline; +} + +.show-card-summary { + font-size: 0.92rem; + line-height: 1.4; + color: #d4d4d8; /* High contrast muted text */ + + /* CSS Line Clamp */ + display: -webkit-box; + -webkit-line-clamp: 4; /* Limits description to 4 lines */ + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} + +.show-card-meta { + background-color: #18181b; + border-top: 1px solid #27272a; + padding: 12px 14px; + border-radius: 6px; + display: flex; + flex-wrap: wrap; + gap: 12px 20px; + font-size: 0.9rem; + margin-top: auto; +} + +.show-card-meta p { + margin: 0; + color: #a1a1aa; +} + +/* Episodes Grid Layout */ +.episodes-container { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 24px; +} + +.episode-card { + background-color: #121214; + border: 2px solid #27272a; + border-radius: 10px; + overflow: hidden; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.6); + display: flex; + flex-direction: column; + transition: + border-color 0.15s ease, + transform 0.15s ease; +} + +.episode-card:focus-within, +.episode-card:hover { + border-color: #38bdf8; + transform: translateY(-3px); +} + +.episode-header { + background-color: #18181b; + padding: 14px 16px; + text-align: center; + border-bottom: 1px solid #27272a; +} + +.episode-header h3 { + margin: 0; + font-size: 1.1rem; + color: #38bdf8; +} + +.episode-card img { + width: 100%; + height: 160px; + object-fit: cover; + background-color: #27272a; +} + +.episode-summary { + padding: 16px; + font-size: 0.92rem; + line-height: 1.5; + color: #d4d4d8; + flex: 1; +} + +/* TVMaze Footer */ +#tvmaze-attribution { + text-align: center; + padding: 24px 16px; + color: #a1a1aa; + font-size: 0.9rem; + border-top: 1px solid #27272a; + margin-top: 40px; +} + +#tvmaze-attribution a { + color: #38bdf8; + font-weight: 600; + text-decoration: underline; +} + +#tvmaze-attribution a:hover, +#tvmaze-attribution a:focus { + color: #ffffff; + outline: 3px solid #38bdf8; + outline-offset: 2px; +} + +/* Responsive adjustment */ +@media (max-width: 820px) { + .shows-container { + grid-template-columns: 1fr; + } +}