https://console.cloud.google.com/welcome?project=invertible-vent-315511
--> 구글 API 생성
- MovieFinder2023 API 프로젝트 생성
- 라이브러리 - YouTube Data API v3 - 사용
- 사용자 인증 정보 만들기 - api 키 따로 작성 후 완료
- OAuth 동의 화면 - 외부 - 만들기 - MovieFinder2023 / 내 이메일 주소 작성 / 개발자 연락처 정보에 내 이메일 주소 작성
MovieFinder
1) 참조 - Nuget 패키지 관리 - MahApps.Metro 설치
2) App.xaml의 Application.Resources 부분 수정
3) https://www.themoviedb.org/ API 발급
- TMDB API URL
https://api.themoviedb.org/3/search/movie?api_key=dd21bad55619f84e6e2823be028cbba2&language=ko-KR&page=1&include_adult=false&query=%EC%9D%B8%ED%84%B0%EC%8A%A4%ED%85%94%EB%9D%BC- TMDB Poster URL
https://image.tmdb.org/t/p/w300_and_h450_bestv2/zDNAeWU0PxKolEX1D8Vn1qWhGjH.jpg4) Youtube Api Key(구글에서 발급)
https://console.cloud.google.com/
AIzaSyCRs0FAqizh_j_LMqren845f3Bwrs4Nhk85) 참조 - 참조추가 - System.Web 추가
6) 참조 - 누겟 패키지 관리 - Newtonsoft.Json 설치
App.xaml
<Application x:Class="wpf11_MovieFinder.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:wpf11_MovieFinder" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> <!-- MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive! --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" /> <!-- Theme setting --> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Emerald.xaml" /> </ResourceDictionary.MergedDictionaries> </ResourceDictionary> </Application.Resources> </Application>
MainWindow.xaml
<mah:MetroWindow x:Class="wpf11_MovieFinder.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls" xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks" xmlns:local="clr-namespace:wpf11_MovieFinder" mc:Ignorable="d" Title="moviefinder 2023" Height="450" Width="800" MinHeight="385" MinWidth="645" FontFamily="NanumGothic"> <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="2*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="60"/> <RowDefinition Height="1*"/> <RowDefinition Height="80"/> </Grid.RowDefinitions> <!--영화명 검색 부분--> <Grid Grid.Row="0" Grid.Column="0"> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <TextBox x:Name="TxtMovieName" Grid.Column="0" FontSize="14" Margin="5,10" mah:TextBoxHelper.Watermark="검색할 영화명 입력" mah:TextBoxHelper.UseFloatingWatermark="True" mah:TextBoxHelper.ClearTextButton="True" KeyDown="TxtMovieName_KeyDown"/> <Button x:Name="BtnSearchMovie" Grid.Column="1" FontSize="14" Margin="5,10" Content="검색" Style="{StaticResource MahApps.Styles.Button.Square.Accent}" Click="BtnSearchMovie_Click"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <iconPacks:PackIconModern Kind="Magnify" Margin="5"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> </Grid> <!--데이터 그리드 영역--> <DataGrid x:Name="GrdResult" Grid.Row="1" Grid.Column="0" Margin="5" IsReadOnly="True" Style="{StaticResource MahApps.Styles.DataGrid.Azure}" ItemsSource="{Binding}"/> <!--포스터 영역--> <Grid Grid.Row="0" Grid.Column="1" Grid.RowSpan="2"> <GroupBox Header="포스터" Margin="10" mah:HeaderedControlHelper.HeaderFontSize="15" mah:HeaderedControlHelper.HeaderHorizontalContentAlignment="Center" mah:HeaderedControlHelper.HeaderFontFamily="NanumGothic" mah:HeaderedControlHelper.HeaderFontWeight="Bold"> <Image x:Name="ImgPoster" Source="No_Picture.png" Margin="15,5"/> </GroupBox> </Grid> <!--버튼 영역--> <StackPanel Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal"> <Button x:Name="BtnAddFavorite" Content="즐겨찾기 추가" Margin="5,20" FontSize="12" Style="{StaticResource MahApps.Styles.Button.Square.Accent}"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <iconPacks:PackIconModern Kind="ListAdd" Margin="5"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> <Button x:Name="BtnViewFavorite" Content="즐겨찾기 보기" Margin="5,20" FontSize="12" Style="{StaticResource MahApps.Styles.Button.Square.Accent}"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <iconPacks:PackIconModern Kind="List" Margin="5"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> <Button x:Name="BtnDelFavorite" Content="즐겨찾기 삭제" Margin="5,20" FontSize="12" Style="{StaticResource MahApps.Styles.Button}"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <iconPacks:PackIconModern Kind="ListDelete" Margin="5"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> <Button x:Name="BtnWatchTrailer" Content="예고편 보기" Margin="5,20" FontSize="12" Style="{StaticResource MahApps.Styles.Button.Flat}"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <iconPacks:PackIconModern Kind="YoutubePlay" Margin="5"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> <Button x:Name="BtnNaverMovie" Content="네이버 영화" Foreground="#099A49" Margin="5,20" FontSize="12" Click="BtnNaverMovie_Click" Style="{StaticResource MahApps.Styles.Button}"> <Button.ContentTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <Image Source="naver.png" Width="20"/> <TextBlock Text="{Binding}" Margin="5"/> </StackPanel> </DataTemplate> </Button.ContentTemplate> </Button> </StackPanel> </Grid> </mah:MetroWindow>
MainWindow.xaml.cs
using MahApps.Metro.Controls; using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; using System.Web; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using wpf11_MovieFinder.Logics; using wpf11_MovieFinder.Models; namespace wpf11_MovieFinder { /// <summary> /// MainWindow.xaml에 대한 상호 작용 논리 /// </summary> public partial class MainWindow : MetroWindow { public MainWindow() { InitializeComponent(); } private async void BtnNaverMovie_Click(object sender, RoutedEventArgs e) { await Commons.ShowMessageAsync("네이버 영화", "네이버 영화 사이트로 이동합니다!"); } //네이버 API 사용 네이버 영화 검색 버튼 private async void BtnSearchMovie_Click(object sender, RoutedEventArgs e) { if(string.IsNullOrEmpty(TxtMovieName.Text)) { await Commons.ShowMessageAsync("검색", "검색할 영화명을 입력하세요."); return; } if(TxtMovieName.Text.Length<=1)//두글자는 써줘라 { await Commons.ShowMessageAsync("검색", "검색어를 2자이상 입력하세요."); return; } try {// 실제 검색 메서드 SearchMovie(TxtMovieName.Text); } catch(Exception ex) { await Commons.ShowMessageAsync("오류", $"오류 발생 : {ex.Message}"); } } //textBox에서 엔터 누를 시 검색 private void TxtMovieName_KeyDown(object sender, KeyEventArgs e) { if(e.Key==Key.Enter) { BtnSearchMovie_Click(sender, e); } } //실제 검색 메서드 private void SearchMovie(string movieName) { string tmdb_apiKey = "dd21bad55619f84e6e2823be028cbba2"; string encoding_movieName = HttpUtility.UrlEncode(movieName, Encoding.UTF8); string openApiUri = $@"https://api.themoviedb.org/3/search/movie?api_key={tmdb_apiKey}&language=ko-KR&page=1&include_adult=false&query={encoding_movieName}"; string result = string.Empty; //결과값 //api 실행할 객체 WebRequest req = null; WebResponse res = null; StreamReader reader = null; // TMDB API 요청 try { req = WebRequest.Create(openApiUri);//URL을 넣어 객체 생성 //Naver Api 헤더 설정 res=req.GetResponse(); //요청한 결과를 응답에 할당 reader = new StreamReader(res.GetResponseStream()); result = reader.ReadToEnd();//json 결과 텍스트로 저장 Debug.WriteLine(result); } catch (Exception ex) { throw ex; } finally { reader.Close(); res.Close(); } //result를 json으로 변경 var jsonResult=JObject.Parse(result); var total = Convert.ToInt32(jsonResult["total_results"]);//전체 검색 결과 수 var items = jsonResult["results"]; //items를 데이터 그리드에 표시 var json_array = items as JArray; var movieItems = new List<MovieItem>();//json에서 넘어온 배열을 담을 장소 foreach(var val in json_array) { var MovieItem = new MovieItem() { Id = Convert.ToInt32(val["id"]), Title = Convert.ToString(val["title"]), Original_Title = Convert.ToString(val["original_title"]), Release_Date = Convert.ToString(val["release_date"]), Vote_Average = Convert.ToDouble(val["vote_average"]) }; movieItems.Add(MovieItem); } this.DataContext=movieItems; } } }
Logics/Commons.cs
using MahApps.Metro.Controls; using MahApps.Metro.Controls.Dialogs; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; namespace wpf11_MovieFinder.Logics { internal class Commons { //매트로 다이얼로그창을 위한 정적 메서드 public static async Task<MessageDialogResult> ShowMessageAsync(string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative) { return await ((MetroWindow)Application.Current.MainWindow).ShowMessageAsync(title, message, style, null); } } }
Models/Movieitem.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace wpf11_MovieFinder.Models { public class MovieItem { public bool Adult { get; set; } public int Id { get; set; } public string Original_Language { get; set; } public string Original_Title { get; set;} public string Overview { get; set; } public double Popularity { get; set; } public string Poster_Path { get; set; } public string Release_Date { get; set; } public string Title { get; set; } public double Vote_Average { get; set; } } }